2002-07-24 Joshua Sled <jsled@asynchronous.org>

* src/scm/fin.scm: Made the exposed calcualtion functions output
	positive values.

	* src/gnome/window-main.c (gnc_main_window_create_menus): Added
	accelerators to SX-related menu items.

	* src/gnome/druid-loan.c: Primary change: actually create the
	Scheduled Transactions which are setup by the user.  Miscellaneous
	other cleanups, text, layout and consistency changes.

	* src/gnome/dialog-sxsincelast.c: Support handling of the
	instance-count in forward-looking transaction creation.  Simplfied
	some of the internal data-representation regarding lists of items
	to be created [removed autoCreateTuple, now uses toCreateTuple].
	Removed some DEBUGging output.  Handles setting up the implicit
	'i' variable.

	* src/gnome/dialog-sx-from-trans.c (sxftd_compute_sx): Create SXes
	with an appropriate initial instance-count value.

	* src/gnome/dialog-scheduledxaction.c
	(schedXact_editor_populate): Create SXes with an appropriate
	initial instance-count value.

	* src/engine/SchedXaction.[ch]: Added support for an
	instance-count, in order to support an implicit 'i' [of N]
	variable to SX formula/function processing.

	* src/engine/SX-ttinfo.c (gnc_ttsplitinfo_free): Made the
	ttsplitinfo_free'ing a bit safer.

	* src/calculation/expression_parser.c: Added support for
	parsing/handling quoted strings.  Intended to be parameters to
	functions.  Fixed bug regarding nested handling of strings in the
	parser.

	* src/backend/file/gnc-schedxaction-xml-v2.c: Added support for
	saving/restoring instance-count field of SXes.

	* src/app-utils/test/test-exp-parser.c
	(run_parser_test): Fixed pass/fail indication check.
	(test_parser): Added tests for string params to functions.

	* ChangeLog: Added entry I forgot from last time.

	* src/app-utils/gnc-exp-parser.c (func_op): Added support for
	typed parameters to functions; params are either numerics or
	strings.  Result of function is now parsed correctly.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@7125 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Joshua Sled 2002-07-24 22:04:57 +00:00
parent 2a990a6cfd
commit 135289725c
19 changed files with 1342 additions and 2223 deletions

View File

@ -1,3 +1,54 @@
2002-07-24 Joshua Sled <jsled@asynchronous.org>
* src/scm/fin.scm: Made the exposed calcualtion functions output
positive values.
* src/gnome/window-main.c (gnc_main_window_create_menus): Added
accelerators to SX-related menu items.
* src/gnome/druid-loan.c: Primary change: actually create the
Scheduled Transactions which are setup by the user. Miscellaneous
other cleanups, text, layout and consistency changes.
* src/gnome/dialog-sxsincelast.c: Support handling of the
instance-count in forward-looking transaction creation. Simplfied
some of the internal data-representation regarding lists of items
to be created [removed autoCreateTuple, now uses toCreateTuple].
Removed some DEBUGging output. Handles setting up the implicit
'i' variable.
* src/gnome/dialog-sx-from-trans.c (sxftd_compute_sx): Create SXes
with an appropriate initial instance-count value.
* src/gnome/dialog-scheduledxaction.c
(schedXact_editor_populate): Create SXes with an appropriate
initial instance-count value.
* src/engine/SchedXaction.[ch]: Added support for an
instance-count, in order to support an implicit 'i' [of N]
variable to SX formula/function processing.
* src/engine/SX-ttinfo.c (gnc_ttsplitinfo_free): Made the
ttsplitinfo_free'ing a bit safer.
* src/calculation/expression_parser.c: Added support for
parsing/handling quoted strings. Intended to be parameters to
functions. Fixed bug regarding nested handling of strings in the
parser.
* src/backend/file/gnc-schedxaction-xml-v2.c: Added support for
saving/restoring instance-count field of SXes.
* src/app-utils/test/test-exp-parser.c
(run_parser_test): Fixed pass/fail indication check.
(test_parser): Added tests for string params to functions.
* ChangeLog: Added entry I forgot from last time.
* src/app-utils/gnc-exp-parser.c (func_op): Added support for
typed parameters to functions; params are either numerics or
strings. Result of function is now parsed correctly.
2002-07-24 Christian Stimming <stimming@tuhh.de>
* src/import-export/hbci/glade/hbci.glade: Some HBCI GUI work --
@ -13,6 +64,16 @@
* src/backend/file/gnc-backend-file.c: File permission fix by Matt
Brubeck <mbrubeck@cs.hmc.edu>
2002-07-12 Joshua Sled <jsled@asynchronous.org>
* src/gnome/glade/sched-xact.glade: Glade-side UI cleanup.
* src/gnome/druid-loan.c: Many updates; now uses GNCAccountSel,
more inter-page consistency checks. UI cleanup
* src/gnome-utils/gnc-account-sel.[ch]: Added; GTK combobox for
selecting an Account.
2002-07-11 Derek Atkins <derek@ihtfp.com>
* change gncEntry->account into gncEntry->invAccount and

View File

@ -350,6 +350,8 @@ func_op( const char *fname,
{
SCM scmFn, scmArgs, scmTmp;
int i;
var_store *vs;
gchar *str;
gnc_numeric n, *result;
GString *realFnName;
@ -365,15 +367,37 @@ func_op( const char *fname,
scmArgs = gh_list( SCM_UNDEFINED );
for ( i=0; i<argc; i++ ) {
/* cons together back-to-front. */
n = *(gnc_numeric*)argv[argc - i - 1];
vs = (var_store*)argv[argc - i - 1];
switch ( vs->type ) {
case VST_NUMERIC:
n = *(gnc_numeric*)(vs->value);
scmTmp = gh_double2scm( gnc_numeric_to_double( n ) );
break;
case VST_STRING:
str = (char*)(vs->value);
scmTmp = gh_str2scm( str, strlen(str) );
break;
default:
/* FIXME: error */
printf( "argument %d not a numeric or string [type = %d]\n",
i, vs->type );
return NULL;
break; /* notreached */
}
scmArgs = gh_cons( scmTmp, scmArgs );
}
scmTmp = gh_apply( scmFn, scmArgs );
result = g_new0( gnc_numeric, 1 );
*result = double_to_gnc_numeric( gh_scm2double(scmTmp), 1,
GNC_DENOM_SIGFIG | (6<<8) );
*result = double_to_gnc_numeric( gh_scm2double(scmTmp),
GNC_DENOM_AUTO,
GNC_DENOM_SIGFIGS(6) | GNC_RND_ROUND );
/* I'm not sure why this explicit negation step is necessary, but it
* doesn't seem like it should be. */
if ( gh_scm2double( scmTmp ) < 0 ) {
*result = gnc_numeric_neg( *result );
}
/* FIXME: cleanup scmArgs = gh_list, cons'ed cells? */
return (void*)result;
}

View File

@ -8,6 +8,8 @@
#include "gnc-numeric.h"
#include "test-stuff.h"
void real_main (int argc, char **argv);
static GList *tests = NULL;
typedef struct
@ -62,12 +64,12 @@ run_parser_test (TestNode *node)
succeeded = gnc_exp_parser_parse (node->exp, &result, &error_loc);
{
int pass;
pass = succeeded;
pass ^= node->should_succeed;
pass = !pass;
printf( "%0.2f [%s]\n",
( ( pass && node->should_succeed ) ?
gnc_numeric_to_double( result ) : 0.0 ),
pass = (succeeded == node->should_succeed);
if ( pass && node->should_succeed ) {
pass &= gnc_numeric_equal( result, node->expected_result );
}
printf( "%0.4f [%s]\n",
gnc_numeric_to_double( result ),
(pass ? "PASS" : "FAIL" ) );
}
@ -139,7 +141,7 @@ test_parser (void)
"- 42.72 + 13.32 + 15.48 + 23.4 + 115.4",
gnc_numeric_create(35897, 100) );
gh_eval_str( "(define (plus a b) (+ a b))" );
gh_eval_str( "(define (gnc:plus a b) (+ a b))" );
add_pass_test( "plus( 1 : 2 ) + 3", NULL, gnc_numeric_create( 6, 1 ) );
add_pass_test( "plus( 1 : 2 ) * 3", NULL, gnc_numeric_create( 9, 1 ) );
add_pass_test( "plus( 1 + 2 : 3 ) * 5", NULL, gnc_numeric_create( 30, 1 ) );
@ -148,14 +150,31 @@ test_parser (void)
add_pass_test( "plus( plus( 1 : 2 ) : 3 )", NULL, gnc_numeric_create( 6, 1 ) );
add_pass_test( "plus( 4 : plus( plus( 1 : 2 ) : 3))", NULL, gnc_numeric_create( 10, 1 ) );
gh_eval_str( "(define (foo a b) (+ a b))" );
add_pass_test( "foo( 1 : 2 ) + 4", NULL, gnc_numeric_create( 7, 1 ) );
gh_eval_str( "(define (gnc:foo a b) (- a b))" );
add_pass_test( "foo( 1 : 2 ) + 4", NULL, gnc_numeric_create( 3, 1 ) );
add_pass_test( "foo( (1 + 2 * 3) : 4 ) + 5",
NULL, gnc_numeric_create( 16, 1 ) );
NULL, gnc_numeric_create( 8, 1 ) );
add_pass_test( "foo( 1 : 2 ) + foo( 3 : 4 ) + 5",
NULL, gnc_numeric_create( 15, 1 ) );
add_pass_test( "foo( a = 42 : foo( foo( 1 : 2 ) : 6 * 7 )) + a",
NULL, gnc_numeric_create( 129, 1 ) );
NULL, gnc_numeric_create( 3, 1 ) );
add_pass_test( "foo( a = 42 : foo( plus( 1 : 2 ) : 6 * 7 )) + a",
NULL, gnc_numeric_create( 123, 1 ) );
gh_eval_str( "(define (gnc:test_str str b)"
" (+ b (cond ((equal? str \"one\") 1)"
" ((equal? str \"two\") 2)"
" ((equal? str \"three\") 3)"
" (0))))" );
add_pass_test( "test_str( \"one\" : 1 )", NULL, gnc_numeric_create( 2, 1 ) );
add_pass_test( "test_str( \"two\" : 2 )", NULL, gnc_numeric_create( 4, 1 ) );
add_fail_test( "test_str( 3 : \"three\" )", NULL, 0 );
add_pass_test( "test_str( \"asdf\" : 1 )", NULL, gnc_numeric_create( 1, 1 ) );
add_fail_test( "\"asdf\" + 0", NULL, 0 );
gh_eval_str( "(define (gnc:blindreturn val) val)" );
add_pass_test( "blindreturn( 123.1 )", NULL, gnc_numeric_create( 1231, 10 ) );
add_pass_test( "blindreturn( 123.01 )", NULL, gnc_numeric_create( 12301, 100 ) );
add_pass_test( "blindreturn( 123.001 )", NULL, gnc_numeric_create( 123001, 1000 ) );
run_parser_tests ();
@ -163,7 +182,7 @@ test_parser (void)
success ("shutdown expression parser");
}
int
void
real_main (int argc, char **argv)
{
/* set_should_print_success (TRUE); */
@ -176,5 +195,5 @@ int main( int argc, char **argv )
{
/* do things this way so we can test scheme function calls from expressions */
gh_enter( argc, argv, real_main );
return 0;
}

View File

@ -59,6 +59,7 @@ static short module = MOD_SX;
* <sx:autoCreateNotify>n</sx:autoCreateNotify>
* <sx:advanceCreateDays>0</sx:advanceCreateDays>
* <sx:advanceRemindDays>5</sx:advanceRemindDays>
* <sx:instanceCount>100</sx:instanceCount>
* <sx:lastOccur>
* <gdate>2001-02-28</gdate>
* </sx:lastOccur>
@ -80,6 +81,7 @@ static short module = MOD_SX;
* <sx:end type="date">
* <gdate>2004-03-20</gdate>
* </sx:end>
* <sx:instanceCount>100</sx:instanceCount>
* <sx:freq>
* <!-- freqspec tree -->
* </sx:freq>
@ -88,6 +90,7 @@ static short module = MOD_SX;
* <sx:id type="guid">...</sx:id>
* <sx:name>Loan 2</sx:name>
* <sx:manual-conf>f</sx:manual-conf>
* <sx:instanceCount>100</sx:instanceCount>
* <sx:start>
* <gdate>2000-12-31</gdate>
* </sx:start>
@ -113,6 +116,7 @@ static short module = MOD_SX;
#define SX_AUTOCREATE_NOTIFY "sx:autoCreateNotify"
#define SX_ADVANCE_CREATE_DAYS "sx:advanceCreateDays"
#define SX_ADVANCE_REMIND_DAYS "sx:advanceRemindDays"
#define SX_INSTANCE_COUNT "sx:instanceCount"
#define SX_START "sx:start"
#define SX_LAST "sx:last"
#define SX_NUM_OCCUR "sx:num-occur"
@ -139,6 +143,7 @@ gnc_schedXaction_dom_tree_create(SchedXaction *sx)
xmlNodePtr ret;
xmlNodePtr fsNode;
GDate *date;
gint instCount;
const GUID *templ_acc_guid;
templ_acc_guid = xaccAccountGetGUID(sx->template_acct);
@ -163,6 +168,10 @@ gnc_schedXaction_dom_tree_create(SchedXaction *sx)
xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_REMIND_DAYS,
sx->advanceRemindDays));
instCount = gnc_sx_get_instance_count( sx, NULL );
xmlAddChild( ret, int_to_dom_tree( SX_INSTANCE_COUNT,
instCount ) );
xmlAddChild( ret,
gdate_to_dom_tree( SX_START,
xaccSchedXactionGetStartDate(sx) ) );
@ -318,6 +327,22 @@ sx_set_date( xmlNodePtr node, SchedXaction *sx,
return TRUE;
}
static
gboolean
sx_instcount_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gint64 instanceNum;
if ( ! dom_tree_to_integer( node, &instanceNum ) ) {
return FALSE;
}
gnc_sx_set_instance_count( sx, instanceNum );
return TRUE;
}
static
gboolean
sx_start_handler( xmlNodePtr node, gpointer sx_pdata )
@ -436,6 +461,7 @@ struct dom_tree_handler sx_dom_handlers[] = {
{ SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
{ SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
{ SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
{ SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
{ SX_START, sx_start_handler, 1, 0 },
{ SX_LAST, sx_last_handler, 0, 0 },
{ SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },

View File

@ -388,7 +388,7 @@ typedef struct parser_env
const char *parse_str;
char radix_point;
char group_char;
char name[50];
char name[128];
char Token;
char asn_op;
@ -417,6 +417,7 @@ parser_env;
#define ARG_TOKEN ':'
#define VAR_TOKEN 'V'
#define NUM_TOKEN 'I'
#define STR_TOKEN '"'
#define STACK_INIT 50
@ -671,6 +672,7 @@ get_named_var (parser_env_ptr pe)
else
bv->next_var = retp;
retp->variable_name = g_strdup (pe->name);
retp->type = VST_NUMERIC;
retp->value =
pe->trans_numeric ("0", pe->radix_point, pe->group_char, NULL);
}
@ -691,6 +693,7 @@ get_unnamed_var (parser_env_ptr pe)
retp = &(pe->unnamed_vars[cntr]);
retp->variable_name = NULL;
retp->use_flag = USED_VAR;
retp->type = VST_NUMERIC;
if (retp->value)
{
pe->free_numeric (retp->value);
@ -756,8 +759,8 @@ next_token (parser_env_ptr pe)
add_token (pe, *str_parse++);
if (*str_parse == ASN_OP)
{
/* BUG/FIXME: this allows '(=' and ')=' [?], neither of which make
* sense. */
/* BUG/FIXME: this seems to allow '(=' and ')=' [?], neither of which
* make sense. */
if (pe->Token != ASN_OP)
{
str_parse++;
@ -768,6 +771,18 @@ next_token (parser_env_ptr pe)
pe->error_code = UNDEFINED_CHARACTER;
} /* endif */
}
/* test for string */
else if ( *str_parse == '"' ) {
nstr = pe->name;
/* skip over the '"'. */
str_parse++;
do {
*nstr++ = *str_parse++;
} while ( *str_parse != '"' );
*nstr = EOS;
str_parse++;
add_token( pe, STR_TOKEN );
}
/* test for name */
else if (isalpha (*str_parse)
|| (*str_parse == '_'))
@ -818,15 +833,6 @@ next_token (parser_env_ptr pe)
pe->parse_str = str_parse;
} /* next_token */
/* evaluate function operators
* <name>( arg0, arg1, ... )
*/
static void
function_op( parser_env_ptr pe )
{
}
/* evaluate assignment operators,
* =
* +=
@ -834,6 +840,7 @@ function_op( parser_env_ptr pe )
* \=
* *=
*/
/* FIXME: add non-numeric checking. */
static void
assignment_op (parser_env_ptr pe)
{
@ -913,6 +920,7 @@ assignment_op (parser_env_ptr pe)
} /* assignment_op */
/* evaluate addition, subtraction operators */
/* FIXME: add non-numeric checking. */
static void
add_sub_op (parser_env_ptr pe)
{
@ -972,6 +980,7 @@ add_sub_op (parser_env_ptr pe)
} /* add_sub_op */
/* evaluate multiplication, division operators */
/* FIXME: add non-numeric checking. */
static void
multiply_divide_op (parser_env_ptr pe)
{
@ -1036,15 +1045,25 @@ multiply_divide_op (parser_env_ptr pe)
* numerics
* grouped expressions, "()"
* functions [ <name>( [exp, exp, ..., exp] ) ]
* strings
*/
static void
primary_exp (parser_env_ptr pe)
{
var_store_ptr rslt = NULL;
char *fnIdent;
char *ident = NULL;
int funcArgCount;
char LToken = pe->Token;
/* If we are in a state where the non-stacked 'pe->name' is valuable, then
* save it before we process the next token. */
switch ( LToken ) {
case FN_TOKEN:
case STR_TOKEN:
ident = g_strdup( pe->name );
break;
}
next_token (pe);
if (pe->error_code)
return;
@ -1099,7 +1118,6 @@ primary_exp (parser_env_ptr pe)
break;
case FN_TOKEN:
fnIdent = pe->name;
funcArgCount = 0;
do {
@ -1126,18 +1144,28 @@ primary_exp (parser_env_ptr pe)
argv = g_new0( void*, funcArgCount );
for ( i=0; i<funcArgCount; i++ ) {
/* fill back-to-front */
/* fill, in back-to-front order, the funcArgCount tokens we just
* parsed out of the expression into a argument list to hand back
* to the caller's func_op callback. */
val = pop(pe);
argv[funcArgCount - i - 1] = val->value;
argv[funcArgCount - i - 1] = val;
}
rslt = get_unnamed_var(pe);
rslt->value = (*pe->func_op)( fnIdent, funcArgCount, argv );
rslt->value = (*pe->func_op)( ident, funcArgCount, argv );
for ( i=0; i<funcArgCount; i++ ) {
free_var( argv[i], pe );
}
g_free( argv );
g_free( ident );
if ( rslt->value == NULL ) {
pe->error_code = NOT_A_FUNC;
add_token( pe, EOS );
return;
}
}
next_token(pe);
@ -1146,6 +1174,11 @@ primary_exp (parser_env_ptr pe)
case VAR_TOKEN:
rslt = get_named_var (pe);
break;
case STR_TOKEN:
rslt = get_unnamed_var( pe );
rslt->type = VST_STRING;
rslt->value = ident;
break;
} /* endswitch */
if (rslt != NULL)

View File

@ -69,11 +69,18 @@ ParseError;
*/
typedef struct var_store *var_store_ptr;
/* the type of entity contained in the var_store */
typedef enum {
VST_NUMERIC = 0,
VST_STRING
} VarStoreType;
typedef struct var_store
{
char *variable_name; /* variable name if variable, NULL otherwise */
char use_flag; /* flag if variable has been assigned to */
char assign_flag; /* flag if variable is used */
VarStoreType type;
void *value; /* pointer to implementation defined numeric value */
var_store_ptr next_var; /* pointer to next variable in linked list */
}

View File

@ -476,7 +476,6 @@ http://www.interest.com/hugh/calc/mort_links.html
Druid Feedback:
<Wilddev> jsled: <auspex> Wilddev: The labels need colons, mnemonics, and right-alignment.
<Wilddev> <auspex> Wilddev: It may be worthwhile for gnucash to create GtkSpinButton subclasses which show the percent symbol and others within the field.
<Wilddev> <auspex> Wilddev: I don't know how complicated that will be.
@ -495,3 +494,29 @@ Druid Feedback:
<jsled> Hmm. Okay. The between-transaction period is a frequency editor on the Repayment page.
<Wilddev> <auspex> I'm wondering if "Original Principal" should be a vulgate
such as "Loan Amount"
----------
Expression changes, round 2
We need the following abilities in order to get mortgage/loan repayment
working:
. Ability to get the original value of an account
. [perhaps, ability to reference an external value?]
. Ability to get the present value of an account
. Ability to get the current i in an "i-of-N" sequence
As well, it'd be nice to have:
. some sort of signature checking on functions in expressions
. safe[r] error handling?
We decide that the original/present value of the account should be handled in
scheme, and thus we actually need a way to reference accounts down to the
scheme expressions. We decide to use the Quote symbols to refer to a string
literal. The expression parser should be modified to parse this.
----------
The current 'i' and 'N' are going to be handled by having a list of
predefined variables which the user cannot have access to. For the time
being, this is 'i' and 'N'.

View File

@ -191,9 +191,13 @@ gnc_ttsplitinfo_malloc(void)
void
gnc_ttsplitinfo_free(TTSplitInfo *ttsi)
{
if ( ttsi->action )
g_free(ttsi->action);
if ( ttsi->memo )
g_free(ttsi->memo);
if ( ttsi->credit_formula )
g_free(ttsi->credit_formula);
if ( ttsi->debit_formula )
g_free(ttsi->debit_formula);
g_free(ttsi);
return;

View File

@ -47,7 +47,6 @@ void gnc_ttinfo_set_num(TTInfo *tti, const char *num);
/* this one points to a persistent pointer so ownership isn't relevant */
void gnc_ttinfo_set_currency(TTInfo *tti, gnc_commodity *common_currency);

View File

@ -51,6 +51,7 @@ typedef struct _temporalStateData {
GDate end_date;
gint num_occur_total;
gint num_occur_rem;
gint num_inst;
} temporalStateData;
/** Local Prototypes *****/
@ -80,6 +81,7 @@ xaccSchedXactionInit( SchedXaction *sx, GNCBook *book)
sx->autoCreateNotify = FALSE;
sx->advanceCreateDays = 0;
sx->advanceRemindDays = 0;
sx->instance_num = 0;
sx->dirty = TRUE;
/* create a new template account for our splits */
@ -507,6 +509,29 @@ xaccSchedXactionGetInstanceAfter( SchedXaction *sx,
return next_occur;
}
gint
gnc_sx_get_instance_count( SchedXaction *sx, void *stateData )
{
gint toRet = -1;
temporalStateData *tsd;
if ( stateData ) {
tsd = (temporalStateData*)stateData;
toRet = tsd->num_inst;
} else {
toRet = sx->instance_num;
}
return toRet;
}
void
gnc_sx_set_instance_count( SchedXaction *sx, gint instanceNum )
{
g_return_if_fail( sx );
sx->instance_num = instanceNum;
}
GList *
xaccSchedXactionGetSplits( SchedXaction *sx )
{
@ -642,10 +667,11 @@ void
xaccSchedXactionIncrSequenceState( SchedXaction *sx,
void *stateData )
{
if ( xaccSchedXactionHasOccurDef( sx ) ) {
temporalStateData *tsd = (temporalStateData*)stateData;
if ( xaccSchedXactionHasOccurDef( sx ) ) {
tsd->num_occur_rem -= 1;
}
tsd->num_inst += 1;
}
void
@ -663,6 +689,7 @@ gnc_sx_create_temporal_state_snapshot( SchedXaction *sx )
toRet->end_date = sx->end_date;
toRet->num_occur_total = sx->num_occurances_total;
toRet->num_occur_rem = sx->num_occurances_remain;
toRet->num_inst = sx->instance_num;
return (void*)toRet;
}
@ -675,6 +702,7 @@ gnc_sx_revert_to_temporal_state_snapshot( SchedXaction *sx, void *stateData )
sx->end_date = tsd->end_date;
sx->num_occurances_total = tsd->num_occur_total;
sx->num_occurances_remain = tsd->num_occur_rem;
sx->instance_num = tsd->num_inst;
sx->dirty = TRUE;
}

View File

@ -118,11 +118,27 @@ void xaccSchedXactionSetNumOccur( SchedXaction *sx, gint numNum );
gint xaccSchedXactionGetRemOccur( SchedXaction *sx );
void xaccSchedXactionSetRemOccur( SchedXaction *sx, gint numRemain );
/**
* Set the instance count. This is incremented by one for every created
* instance of the SX.
* @param stateData may be NULL.
**/
gint gnc_sx_get_instance_count( SchedXaction *sx, void *stateData );
/**
* Sets the instance count to something other than the default. As the
* default is the incorrect value '0', callers should DTRT here.
**/
void gnc_sx_set_instance_count( SchedXaction *sx, gint instanceNum );
GList *xaccSchedXactionGetSplits( SchedXaction *sx );
void xaccSchedXactionSetSplits( SchedXaction *sx, GList *newSplits );
void xaccSchedXactionGetAutoCreate( SchedXaction *sx, gboolean *outAutoCreate, gboolean *outNotify );
void xaccSchedXactionSetAutoCreate( SchedXaction *sx, gboolean newAutoCreate, gboolean newNotify );
void xaccSchedXactionGetAutoCreate( SchedXaction *sx,
gboolean *outAutoCreate,
gboolean *outNotify );
void xaccSchedXactionSetAutoCreate( SchedXaction *sx,
gboolean newAutoCreate,
gboolean newNotify );
gint xaccSchedXactionGetAdvanceCreation( SchedXaction *sx );
void xaccSchedXactionSetAdvanceCreation( SchedXaction *sx, gint createDays );
@ -177,6 +193,9 @@ void xaccSchedXactionSetGUID( SchedXaction *sx, GUID g );
* looking at reminders... and generally thinking about not wanting the
* caller to know every possible thing that needs to be kept track of in a
* forward-looking sequence of SXes.
*
* THESE (3) FUNCTIONS ARE DEPRECATED. See/Use the
* 'temporal_state_snapshot' functions below.
**/
void *xaccSchedXactionCreateSequenceState( SchedXaction *sx );
void xaccSchedXactionIncrSequenceState( SchedXaction *sx, void *stateData );
@ -194,7 +213,8 @@ void xaccSchedXactionDestroySequenceState( void *stateData );
* SX without having to rollback all the individual state changes.
*
* NOTE that this is similar to the above SequenceState interface, and
* perhaps can be seen as entailing the above interface.
* perhaps can be seen as entailing the above interface. In fact, the above
* interface is deprecated in favor of this one.
**/
void *gnc_sx_create_temporal_state_snapshot( SchedXaction *sx );
void gnc_sx_revert_to_temporal_state_snapshot( SchedXaction *sx, void *stateData );

View File

@ -65,6 +65,9 @@ struct gncp_SchedXaction
/* reminaing occurances are as-of the 'last_date'. */
gint num_occurances_remain;
/* the current instance-count of the SX. */
gint instance_num;
gboolean autoCreateOption;
gboolean autoCreateNotify;
gint advanceCreateDays;

View File

@ -465,6 +465,7 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
* Do checks on validity and such, interrupting the user if
* things aren't right.
*
* . support formulas [?!]
* . balancing the SX if contain numeric-only formula data.
* . agreement with create-automagically/notification controls
* X the 'will ever be valid' check should take num-occur vals into
@ -1429,6 +1430,10 @@ schedXact_editor_populate( SchedXactionEditorDialog *sxed )
(gfloat)daysInAdvance );
}
if ( sxed->newsxP ) {
gnc_sx_set_instance_count( sxed->sx, 1 );
}
/* populate the ledger */
{
/* create the split list */

View File

@ -387,6 +387,8 @@ sxftd_compute_sx(SXFromTransInfo *sxfti)
break;
}
gnc_sx_set_instance_count( sx, 1 );
sxftd_add_template_trans( sxfti );
return sxftd_errno;

View File

@ -140,7 +140,7 @@ typedef struct _sxSinceLastData {
GtkProgressBar *prog;
/* Multi-stage processing-related stuff... */
GList /* <autoCreateTuple*> */ *autoCreateList;
GList /* <toCreateTuple*> */ *autoCreateList;
GList /* <toCreateTuple*> */ *toCreateList;
GList /* <reminderTuple*> */ *reminderList;
GList /* <toDeleteTuple*> */ *toRemoveList;
@ -165,12 +165,6 @@ typedef struct _sxSinceLastData {
} sxSinceLastData;
typedef struct autoCreateTuple_ {
SchedXaction *sx;
GList /* <GDate*> */ *instanceList;
} autoCreateTuple;
typedef struct toCreateTuple_ {
SchedXaction *sx;
GList /* <toCreateInstance*> */ *instanceList;
@ -179,6 +173,7 @@ typedef struct toCreateTuple_ {
typedef struct toCreateInstance_ {
GDate *date;
GHashTable *varBindings;
gint instanceNum;
GtkCTreeNode *node;
toCreateTuple *parentTCT;
} toCreateInstance;
@ -197,6 +192,7 @@ typedef struct reminderTuple_ {
typedef struct reminderInstanceTuple_ {
GDate *endDate;
GDate *occurDate;
gint instanceNum;
gboolean isSelected;
reminderTuple *parentRT;
} reminderInstanceTuple;
@ -453,7 +449,6 @@ reminders_page_prep( sxSinceLastData *sxsld )
if ( g_list_length( sxsld->reminderList ) == 0 ) {
w = glade_xml_get_widget( sxsld->gxml,
AUTO_CREATE_NOTIFY_PG );
DEBUG( "Going to auto_create_notify page" );
gnome_druid_set_page( sxsld->sincelast_druid,
GNOME_DRUID_PAGE(w) );
return;
@ -510,7 +505,6 @@ auto_create_prep( GnomeDruidPage *druid_page,
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
if ( ! sxsld->autoCreatedSomething ) {
DEBUG( "Going to to_create page" );
w = glade_xml_get_widget( sxsld->gxml, TO_CREATE_PG );
gnome_druid_set_page( sxsld->sincelast_druid,
GNOME_DRUID_PAGE(w) );
@ -526,7 +520,6 @@ created_prep( GnomeDruidPage *druid_page,
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
if ( !sxsld->createdSomething ) {
DEBUG( "Going to obsolete page" );
w = glade_xml_get_widget( sxsld->gxml, OBSOLETE_PG );
gnome_druid_set_page( sxsld->sincelast_druid,
GNOME_DRUID_PAGE(w) );
@ -541,7 +534,6 @@ obsolete_prep( GnomeDruidPage *druid_page,
GtkWidget *w;
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
if ( g_list_length( sxsld->toRemoveList ) == 0 ) {
DEBUG( "Going to finish page" );
w = glade_xml_get_widget( sxsld->gxml, FINISH_PG );
gnome_druid_set_page( sxsld->sincelast_druid,
GNOME_DRUID_PAGE(w) );
@ -560,7 +552,6 @@ obsolete_next( GnomeDruidPage *druid_page,
toDeleteTuple *tdt;
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
DEBUG( "obsolete_next" );
sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
cl = GTK_CLIST( glade_xml_get_widget( sxsld->gxml,
SX_OBSOLETE_CLIST ) );
@ -569,11 +560,7 @@ obsolete_next( GnomeDruidPage *druid_page,
toDelPtr;
toDelPtr = toDelPtr->next ) {
row = (gint)toDelPtr->data;
DEBUG( "getting row data for SX_OBSOLETE_CLIST row %d",
row );
tdt = (toDeleteTuple*)gtk_clist_get_row_data( cl, row );
DEBUG( "got tdt with sx with name \"%s\"",
xaccSchedXactionGetName( tdt->sx ) );
{
elt = g_list_find( sxList, tdt->sx );
sxList = g_list_remove_link( sxList, elt );
@ -699,8 +686,6 @@ to_create_next( GnomeDruidPage *druid_page,
}
}
DEBUG( "Done with creation; updating created ledger." );
oldQuery = gnc_ledger_display_get_query( sxsld->created_ledger );
newQuery = xaccQueryMerge( oldQuery, q, QUERY_AND );
gnc_ledger_display_set_query( sxsld->created_ledger, newQuery );
@ -925,7 +910,7 @@ sxsincelast_init( sxSinceLastData *sxsld )
}
}
//reminders_page_prep( sxsld );
/*reminders_page_prep( sxsld );*/
gtk_widget_show_all( sxsld->sincelast_window );
process_auto_create_list( sxsld->autoCreateList, sxsld );
@ -952,7 +937,8 @@ generate_instances( SchedXaction *sx,
GList **reminderList,
GList **deadList )
{
GDate gd, *gdToReturn;
GDate gd;
toCreateInstance *tci;
reminderTuple *rt;
reminderInstanceTuple *rit;
void *seqStateData;
@ -966,9 +952,13 @@ generate_instances( SchedXaction *sx,
g_date_strftime( tmpBuf, GNC_D_WIDTH, GNC_D_FMT, &gd );
gdToReturn = g_date_new();
*gdToReturn = gd;
*instanceList = g_list_append( *instanceList, gdToReturn );
tci = g_new0( toCreateInstance, 1 );
tci->date = g_date_new();
*tci->date = gd;
tci->instanceNum = gnc_sx_get_instance_count( sx, seqStateData );
*instanceList = g_list_append( *instanceList, tci );
xaccSchedXactionIncrSequenceState( sx, seqStateData );
gd = xaccSchedXactionGetInstanceAfter( sx, &gd, seqStateData );
@ -990,7 +980,9 @@ generate_instances( SchedXaction *sx,
rt->instanceList = NULL;
while ( g_date_valid(&gd)
&& g_date_compare( &gd, reminderEnd ) <= 0 ) {
g_date_strftime( tmpBuf, GNC_D_WIDTH, GNC_D_FMT, &gd );
rit = g_new0( reminderInstanceTuple, 1 );
rit->endDate = g_date_new();
*rit->endDate = *end;
@ -998,6 +990,7 @@ generate_instances( SchedXaction *sx,
*rit->occurDate = gd;
rit->isSelected = FALSE;
rit->parentRT = rt;
rit->instanceNum = gnc_sx_get_instance_count( sx, seqStateData );
rt->instanceList = g_list_append( rt->instanceList, rit );
@ -1072,7 +1065,8 @@ process_auto_create_list( GList *autoCreateList, sxSinceLastData *sxsld )
{
GList *createdGUIDs = NULL;
GList *thisGUID;
autoCreateTuple *act;
toCreateTuple *tct;
toCreateInstance *tci;
gboolean autoCreateState, notifyState;
Query *q, *dlQuery, *newQuery;
GList *instances;
@ -1084,18 +1078,19 @@ process_auto_create_list( GList *autoCreateList, sxSinceLastData *sxsld )
gtk_progress_configure( GTK_PROGRESS(sxsld->prog), 0, 0,
g_list_length( autoCreateList ) );
for ( ; autoCreateList ; autoCreateList = autoCreateList->next ) {
act = (autoCreateTuple*)autoCreateList->data;
tct = (toCreateTuple*)autoCreateList->data;
xaccSchedXactionGetAutoCreate( act->sx,
xaccSchedXactionGetAutoCreate( tct->sx,
&autoCreateState,
&notifyState );
for ( instances = act->instanceList;
for ( instances = tct->instanceList;
instances;
instances = instances->next ) {
tci = (toCreateInstance*)instances->data;
thisGUID = createdGUIDs = NULL;
create_transactions_on( act->sx,
(GDate*)instances->data,
create_transactions_on( tct->sx,
(GDate*)tci->date,
NULL, &createdGUIDs );
count += g_list_length( createdGUIDs );
@ -1121,7 +1116,7 @@ process_auto_create_list( GList *autoCreateList, sxSinceLastData *sxsld )
}
}
DEBUG( "Finished creating transactions; updating ledger" );
/*DEBUG( "Finished creating transactions; updating ledger" );*/
dlQuery = gnc_ledger_display_get_query( sxsld->ac_ledger );
newQuery = xaccQueryMerge( dlQuery, q, QUERY_AND );
@ -1141,6 +1136,8 @@ add_to_create_list_to_gui( GList *toCreateList, sxSinceLastData *sxsld )
GtkCTreeNode *sxNode;
char *rowText[ TO_CREATE_LIST_WIDTH ];
GList *insts;
int htSize;
gpointer unusedkey, unusedvalue;
ct = GTK_CTREE( glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST ) );
@ -1170,7 +1167,13 @@ add_to_create_list_to_gui( GList *toCreateList, sxSinceLastData *sxsld )
g_date_strftime( rowText[0], GNC_D_WIDTH, GNC_D_FMT, tci->date );
sxsl_get_sx_vars( tci->parentTCT->sx, tci->varBindings );
if ( g_hash_table_size( tci->varBindings ) == 0 ) {
htSize = g_hash_table_size( tci->varBindings );
if ( g_hash_table_lookup_extended( tci->varBindings, "i",
&unusedkey,
&unusedvalue ) ) {
htSize -= 1;
}
if ( htSize == 0 ) {
rowText[1] = "y";
} else {
rowText[1] = "n";
@ -1299,41 +1302,45 @@ processSelectedReminderList( GList *goodList, sxSinceLastData *sxsld )
{
GList *list = NULL;
reminderInstanceTuple *rit;
autoCreateTuple *act;
toCreateTuple *tct;
toCreateInstance *tci;
gboolean autoCreateOpt, notifyOpt;
tct = NULL;
act = NULL;
for ( ; goodList ; goodList = goodList->next ) {
rit = (reminderInstanceTuple*)goodList->data;
DEBUG( "Processing selected reminder \"%s\"",
xaccSchedXactionGetName( rit->parentRT->sx ) );
xaccSchedXactionGetAutoCreate( rit->parentRT->sx,
&autoCreateOpt, &notifyOpt );
if ( autoCreateOpt ) {
for ( list = sxsld->autoCreateList;
list;
list = list->next ) {
act = (autoCreateTuple*)list->data;
// Find any already-existing toCreateTuples to add to...
if ( act->sx == rit->parentRT->sx ) {
tct = (toCreateTuple*)list->data;
/* Find any already-existing toCreateTuples to add to...*/
if ( tct->sx == rit->parentRT->sx ) {
break;
}
}
if ( !list ) {
act = g_new0( autoCreateTuple, 1 );
act->sx = rit->parentRT->sx;
tct = g_new0( toCreateTuple, 1 );
tct->sx = rit->parentRT->sx;
sxsld->autoCreateList =
g_list_append( sxsld->autoCreateList, act );
g_list_append( sxsld->autoCreateList, tct );
}
act->instanceList = g_list_append( act->instanceList,
rit->occurDate );
tci = g_new0( toCreateInstance, 1 );
tci->parentTCT = tct;
tci->date = rit->occurDate;
tci->varBindings = NULL;
tci->instanceNum = rit->instanceNum;
tci->node = NULL;
tct->instanceList =
g_list_append( tct->instanceList, tci );
list = NULL;
list = g_list_append( list, act );
list = g_list_append( list, tct );
process_auto_create_list( list, sxsld );
list = NULL;
} else {
@ -1341,7 +1348,7 @@ processSelectedReminderList( GList *goodList, sxSinceLastData *sxsld )
list;
list = list->next ) {
tct = (toCreateTuple*)list->data;
// Find any already-existing toCreateTuples to add to...
/* Find any already-existing toCreateTuples to add to...*/
if ( tct->sx == rit->parentRT->sx ) {
break;
}
@ -1357,6 +1364,7 @@ processSelectedReminderList( GList *goodList, sxSinceLastData *sxsld )
tci->date = rit->occurDate;
tci->node = NULL;
tci->varBindings = NULL;
tci->instanceNum = rit->instanceNum;
tct->instanceList =
g_list_append( tct->instanceList, tci );
@ -1377,11 +1385,9 @@ sxsincelast_populate( sxSinceLastData *sxsld )
SchedXaction *sx;
void *sx_state;
GDate end, endPlusReminders;
GDate *instDate;
gint daysInAdvance;
gboolean autocreateState, notifyState;
gboolean showIt;
autoCreateTuple *act;
toCreateTuple *tct;
toCreateInstance *tci;
@ -1432,27 +1438,24 @@ sxsincelast_populate( sxSinceLastData *sxsld )
xaccSchedXactionGetAutoCreate( sx, &autocreateState,
&notifyState );
if ( autocreateState ) {
act = g_new0( autoCreateTuple, 1 );
act->sx = sx;
tct = g_new0( toCreateTuple, 1 );
tct->sx = sx;
for ( ; instanceList; instanceList = instanceList->next ) {
instDate = (GDate*)instanceList->data;
act->instanceList =
g_list_append( act->instanceList,
instDate );
tci = (toCreateInstance*)instanceList->data;
tci->parentTCT = tct;
tct->instanceList =
g_list_append( tct->instanceList,
tci );
}
sxsld->autoCreateList =
g_list_append( sxsld->autoCreateList,
act );
tct );
} else {
tct = g_new0( toCreateTuple, 1 );
tct->sx = sx;
for ( ; instanceList; instanceList = instanceList->next ) {
instDate = (GDate*)instanceList->data;
tci = g_new0( toCreateInstance, 1 );
tci = (toCreateInstance*)instanceList->data;
tci->parentTCT = tct;
tci->date = instDate;
tci->node = NULL;
tci->varBindings = NULL;
tct->instanceList =
g_list_append( tct->instanceList, tci );
}
@ -1509,7 +1512,6 @@ sxsincelast_close_handler( gpointer ud )
{
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
DEBUG( "sxsincelast_close_handler" );
gtk_widget_hide( sxsld->sincelast_window );
sxsincelast_save_size( sxsld );
clean_sincelast_dlg( sxsld );
@ -1521,8 +1523,10 @@ static void
andequal_numerics_set( gpointer key, gpointer value, gpointer data )
{
gboolean *allVarsBound = data;
if ( strcmp( (gchar*)key, "i" ) != 0 ) {
*allVarsBound &= (value != NULL);
}
}
static void
sxsincelast_entry_changed( GtkEditable *e, gpointer ud )
@ -1598,7 +1602,6 @@ sxsincelast_destroy( GtkObject *o, gpointer ud )
{
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
DEBUG( "sxsincelast_destroy called\n" );
gnc_unregister_gui_component_by_data( DIALOG_SXSINCELAST_CM_CLASS,
sxsld->sincelast_window );
@ -1614,6 +1617,40 @@ sxsincelast_destroy( GtkObject *o, gpointer ud )
g_free( sxsld );
}
/**
* Used to copy the varBinding GHashTable.
**/
static
void
gnc_sxsl_copy_ea_hash( gpointer key,
gpointer value,
gpointer user_data )
{
gchar *name = (gchar*)key;
gnc_numeric *val = (gnc_numeric*)value;
gnc_numeric *newVal;
GHashTable *table = (GHashTable*)user_data;
newVal = g_new0( gnc_numeric, 1 );
*newVal = gnc_numeric_error( -2 );
if ( val )
*newVal = *val;
g_hash_table_insert( table,
(gpointer)g_strdup( name ),
(gpointer)newVal );
}
static
void
gnc_sxsl_del_vars_table_ea( gpointer key,
gpointer value,
gpointer user_data )
{
g_free( (gchar*)key );
g_free( (gnc_numeric*)value );
}
static gboolean
create_each_transaction_helper( Transaction *t, void *d )
{
@ -1627,6 +1664,8 @@ create_each_transaction_helper( Transaction *t, void *d )
createData *createUD;
toCreateInstance *tci;
gnc_commodity *commonCommodity = NULL;
GHashTable *actualVars;
gnc_numeric *varIValue;
errFlag = FALSE;
@ -1637,15 +1676,25 @@ create_each_transaction_helper( Transaction *t, void *d )
/* FIXME: when we copy the trans_onto_trans, we don't want to copy
the Split's kvp_frames... */
/* FIXME: This should setup the predefined variables 'i' and 'N' */
createUD = (createData*)d;
tci = createUD->tci;
actualVars = g_hash_table_new( g_str_hash, g_str_equal );
if ( tci->varBindings != NULL ) {
g_hash_table_foreach( tci->varBindings,
gnc_sxsl_copy_ea_hash, actualVars );
}
varIValue = g_new0( gnc_numeric, 1 );
*varIValue = gnc_numeric_create( tci->instanceNum, 1 );
g_hash_table_insert( actualVars, "i", varIValue );
newT = xaccMallocTransaction(gnc_get_current_book ());
xaccTransBeginEdit( newT );
/* the action and description/memo are in the template */
gnc_copy_trans_onto_trans( t, newT, FALSE, FALSE );
/* the date is new [by definition :)] */
xaccTransSetDate( newT,
g_date_day( tci->date ),
g_date_month( tci->date ),
@ -1658,7 +1707,8 @@ create_each_transaction_helper( Transaction *t, void *d )
PERR( "\tseen transaction w/o splits. :(" );
return FALSE;
}
do {
for ( ; sList && osList ;
sList = sList->next, osList = osList->next ) {
split = (Split*)sList->data;
/* FIXME: Ick. This assumes that the split lists will be
ordered identically. :( I think it's fair to say they
@ -1683,10 +1733,10 @@ create_each_transaction_helper( Transaction *t, void *d )
acct_guid = kvp_value_get_guid( kvp_val );
acct = xaccAccountLookup( acct_guid,
gnc_get_current_book ());
#if 0
#if 0 /* debug */
DEBUG( "Got account with name \"%s\"",
xaccAccountGetName( acct ) );
#endif /* 0 */
#endif /* 0 -- debug */
if ( commonCommodity != NULL ) {
if ( commonCommodity != xaccAccountGetCommodity( acct ) ) {
PERR( "Common-commodity difference: old=%s, new=%s\n",
@ -1717,17 +1767,18 @@ create_each_transaction_helper( Transaction *t, void *d )
if ( str != NULL
&& strlen(str) != 0 ) {
if ( ! gnc_exp_parser_parse_separate_vars( str, &credit_num,
&parseErrorLoc, tci->varBindings ) ) {
&parseErrorLoc,
actualVars ) ) {
PERR( "Error parsing credit formula \"%s\" at \"%s\": %s",
str, parseErrorLoc, gnc_exp_parser_error_string() );
errFlag = TRUE;
break;
}
#if 0
#if 0 /* debug */
DEBUG( "gnc_numeric::credit: \"%s\" -> %s [%s]",
str, gnc_numeric_to_string( credit_num ),
gnc_numeric_to_string( gnc_numeric_reduce( credit_num ) ) );
#endif /* 0 */
#endif /* 0 -- debug */
}
kvp_val = kvp_frame_get_slot_path( split_kvpf,
@ -1740,18 +1791,19 @@ create_each_transaction_helper( Transaction *t, void *d )
if ( str != NULL
&& strlen(str) != 0 ) {
if ( ! gnc_exp_parser_parse_separate_vars( str, &debit_num,
&parseErrorLoc, tci->varBindings ) ) {
&parseErrorLoc,
actualVars ) ) {
PERR( "Error parsing debit_formula \"%s\" at \"%s\": %s",
str, parseErrorLoc, gnc_exp_parser_error_string() );
errFlag = TRUE;
break;
}
#if 0
#if 0 /* debug */
DEBUG( "gnc_numeric::debit: \"%s\" -> %s [%s]",
str, gnc_numeric_to_string( debit_num ),
gnc_numeric_to_string( gnc_numeric_reduce( debit_num ) ) );
#endif /* 0 */
#endif /* 0 -- debug */
}
final = gnc_numeric_sub_fixed( debit_num, credit_num );
@ -1762,12 +1814,15 @@ create_each_transaction_helper( Transaction *t, void *d )
errFlag = TRUE;
break;
}
#if 0
#if 0 /* debug */
DEBUG( "gnc_numeric::final: \"%s\"",
gnc_numeric_to_string( final ) );
#endif /* 0 */
xaccSplitSetBaseValue( split, final, commonCommodity );
#endif /* 0 -- debug */
xaccSplitSetValue( split, final );
}
#if 0
/* NOT [YET] USED */
kvp_val = kvp_frame_get_slot_path( split_kvpf,
@ -1780,12 +1835,17 @@ create_each_transaction_helper( Transaction *t, void *d )
GNC_SX_AMNT,
NULL);
#endif /* 0 */
/* FIXME:
* . We'd like to store the variable bindings, but this might be
* problematic [if the formulas change in the SX] [?]
*/
} while ( (sList = sList->next) && (osList = osList->next) );
}
/* Cleanup actualVars table. */
{
g_hash_table_foreach( actualVars,
gnc_sxsl_del_vars_table_ea,
NULL );
g_hash_table_destroy( actualVars );
actualVars = NULL;
}
/* set the balancing currency. */
if ( commonCommodity == NULL ) {
@ -1797,7 +1857,7 @@ create_each_transaction_helper( Transaction *t, void *d )
{
kvp_frame *txn_frame;
/* set a kvp-frame element in the transaction indicating and
pointing-to the SX this was created from. */
* pointing-to the SX this was created from. */
txn_frame = xaccTransGetSlots( newT );
if ( txn_frame == NULL ) {
txn_frame = kvp_frame_new();
@ -1875,7 +1935,6 @@ create_transactions_on( SchedXaction *sx,
createdTCT = TRUE;
}
gnc_suspend_gui_refresh();
ag = gnc_book_get_template_group( gnc_get_current_book () );
id = guid_to_string( xaccSchedXactionGetGUID(sx) );
if(ag && id)
@ -1895,9 +1954,19 @@ create_transactions_on( SchedXaction *sx,
{
g_free( id );
}
gnc_resume_gui_refresh();
/* Increment the SX state */
{
gint tmp;
xaccSchedXactionSetLastOccurDate( sx, tci->date );
tmp = gnc_sx_get_instance_count( sx, NULL );
gnc_sx_set_instance_count( sx, tmp+1 );
if ( xaccSchedXactionHasOccurDef( sx ) ) {
tmp = xaccSchedXactionGetRemOccur(sx);
xaccSchedXactionSetRemOccur( sx, tmp-1 );
}
}
if ( createdTCT ) {
g_free( tci );
@ -1992,7 +2061,6 @@ static gboolean
tct_table_entry_key_handle( GtkWidget *widget, GdkEventKey *event, gpointer ud )
{
gnc_numeric *num;
//gchar *entryText;
GtkEntry *ent = NULL;
GString *str;
@ -2059,8 +2127,19 @@ sxsincelast_tc_row_sel( GtkCTree *ct,
return;
}
if ( (varHashSize = g_hash_table_size( tci->varBindings )) == 0 ) {
PINFO( "No variables to deal with" );
/* Get the count of variables; potentially remove the system-defined
* variables if they're present in the expression. */
varHashSize = g_hash_table_size( tci->varBindings );
{
gpointer *foo, *bar;
if ( g_hash_table_lookup_extended( tci->varBindings, "i",
(gpointer)&foo,
(gpointer)&bar ) ) {
varHashSize -= 1;
}
}
if ( varHashSize == 0 ) {
return;
}
@ -2072,19 +2151,25 @@ sxsincelast_tc_row_sel( GtkCTree *ct,
tableIdx = 1;
for ( ; varList ; varList = varList->next ) {
gchar *varName;
GString *gstr;
const gchar *numValueStr;
gnc_numeric *numValue, *tmpNumValue;
varName = (gchar*)varList->data;
if ( strcmp( varName, "i" ) == 0 ) {
continue;
}
gstr = g_string_sized_new(16);
g_string_sprintf( gstr, "%s: ", (gchar*)varList->data );
g_string_sprintf( gstr, "%s: ", varName );
label = gtk_label_new( gstr->str );
gtk_label_set_justify( GTK_LABEL(label), GTK_JUSTIFY_RIGHT );
g_string_free( gstr, TRUE );
entry = gtk_entry_new();
gtk_object_set_data( GTK_OBJECT(entry), "varName",
varList->data );
varName );
gtk_object_set_data( GTK_OBJECT(entry), "tci", tci );
tmpNumValue = g_new0( gnc_numeric, 1 );
*tmpNumValue = gnc_numeric_create( 0, 1 );
@ -2099,7 +2184,7 @@ sxsincelast_tc_row_sel( GtkCTree *ct,
gtk_widget_set_usize( entry, 64, 0 );
numValue = (gnc_numeric*)g_hash_table_lookup( tci->varBindings,
varList->data );
varName );
if ( numValue != NULL ) {
numValueStr =
xaccPrintAmount( *numValue,
@ -2144,14 +2229,14 @@ clean_variable_table( sxSinceLastData *sxsld )
return;
}
do {
for( ; children ; children = children->next ) {
/* Destroy all children after the first [label-continaing]
row... ie, leave the labels in place. */
child = (GtkTableChild*)children->data;
if ( child->top_attach > 0 ) {
toFree = g_list_append( toFree, child->widget );
}
} while ( (children = children->next) );
}
gtk_table_resize( table, 1, 2 );
@ -2503,7 +2588,6 @@ sxsld_ledger_get_parent( GNCLedgerDisplay *ld )
sxSinceLastData *sxsld;
sxsld = (sxSinceLastData*)gnc_ledger_display_get_user_data( ld );
//return (gncUIWidget)sxsld->reg->sheet->window;
return (gncUIWidget)sxsld->sincelast_window;
}

View File

@ -30,6 +30,10 @@
#include "druid-loan.h"
#include "SchedXaction.h"
#include "SX-ttinfo.h"
#include "gnc-book-p.h"
#include "gnc-book.h"
#include "gnc-amount-edit.h"
#include "gnc-account-sel.h"
#include "gnc-component-manager.h"
@ -53,7 +57,6 @@
# define ORIG_PRINC_GNE "orig_princ_gne"
# define ORIG_PRINC_ENTRY "orig_princ_ent"
# define IRATE_SPIN "irate_spin"
# define TYPE_OPT "type_opt"
# define VAR_CONTAINER "type_freq_frame"
# define START_DATE "start_gde"
# define LENGTH_SPIN "len_spin"
@ -61,12 +64,11 @@
# define REMAIN_SPIN "rem_spin"
#define PG_OPTS "loan_opts_pg"
# define OPT_CONTAINER "opt_vbox"
# define OPT_ESCROW "opt_escrow"
# define OPT_ESCROW "opt_escrow_cb"
# define OPT_ESCROW_CONTAINER "opt_escrow_hbox"
#define PG_REPAYMENT "repayment_pg"
# define TXN_NAME "txn_title"
# define REPAY_TABLE "repay_table"
# define AMOUNT_GNE "amount_gne"
# define AMOUNT_ENTRY "amount_ent"
# define REMAINDER_OPT "remain_opt"
# define FREQ_CONTAINER "freq_frame"
@ -91,6 +93,8 @@
* . Frequency <- sensitive
**/
struct LoanDruidData_;
/**
* The data relating to a single "repayment option" -- a potential
* [sub-]transaction in the repayment.
@ -101,7 +105,7 @@ typedef struct RepayOptData_ {
char *txnMemo;
float amount;
gboolean throughEscrowP;
//Account *to;
Account *to;
Account *from; // If NULL { If throughEscrowP, then through escrowP;
// else: undefined.
FreqSpec *fs; // If NULL, part of repayment; otherwise: defined here.
@ -119,9 +123,9 @@ typedef struct RepayOptDataDefault_ {
static RepayOptDataDefault REPAY_DEFAULTS[] = {
/* { name, default txn memo, throughEscrowP } */
{ "Taxes", "Tax Payment", FALSE },
{ "Insurance", "Insurance Payment", FALSE },
{ "PMI", "PMI Payment", FALSE },
{ "Taxes", "Tax Payment", TRUE },
{ "Insurance", "Insurance Payment", TRUE },
{ "PMI", "PMI Payment", TRUE },
{ "Other Expense", "Miscellaneous Payment", FALSE },
{ NULL }
};
@ -130,6 +134,9 @@ static RepayOptDataDefault REPAY_DEFAULTS[] = {
* The UI-side storage of the repayment options.
**/
typedef struct RepayOptUI_ {
/* must be stated this way [instead of 'LoanDruidData*'] because of
* forward decl. */
struct LoanDruidData_ *ldd;
GtkCheckButton *optCb;
GtkCheckButton *escrowCb;
RepayOptData *optData;
@ -138,7 +145,8 @@ typedef struct RepayOptUI_ {
typedef enum {
FIXED = 0,
VARIABLE,
VARIABLE_5_1 = VARIABLE,
VARIABLE_3_1 = VARIABLE,
VARIABLE_5_1,
VARIABLE_7_1,
VARIABLE_10_1,
/* ... FIXME */
@ -164,6 +172,16 @@ typedef struct LoanData_ {
int numPerRemain;
PeriodSize perSize;
char *repMemo;
char *repAmount;
Account *repFromAcct;
Account *repPriAcct;
Account *repIntAcct;
Account *escrowAcct;
int remainderChoice;
FreqSpec *repFreq;
GDate *repStartDate;
int repayOptCount;
RepayOptData **repayOpts;
} LoanData;
@ -201,16 +219,17 @@ typedef struct LoanDruidData_ {
/* opt = options */
GtkVBox *optVBox;
GtkCheckButton *optEscrowCb;
GtkHBox *optEscrowHBox;
GNCAccountSel *optEscrowGAS;
/* rep = repayment */
GtkEntry *repTxnName;
GtkTable *repTable;
GnomeNumberEntry *repAmtGNE;
GtkEntry *repAmtEntry;
GNCAccountSel *repAssetsFromGAS;
GNCAccountSel *repPrincToGAS;
GNCAccountSel *repIntToGAS;
GNCAccountSel *repEscrowToGAS;
GtkEntry *repAmtEntry;
GtkOptionMenu *repRemainderOpt;
GtkFrame *repFreqFrame;
GNCFrequency *repGncFreq;
@ -219,7 +238,8 @@ typedef struct LoanDruidData_ {
GtkEntry *payTxnName;
GnomeNumberEntry *payAmtGNE;
GtkEntry *payAmtEntry;
GNCAccountSel *payAccountGAS;
GNCAccountSel *payAcctFromGAS;
GNCAccountSel *payAcctToGAS;
GtkTable *payTable;
GtkRadioButton *payTxnFreqPartRb;
GtkRadioButton *payTxnFreqUniqRb;
@ -235,42 +255,32 @@ static void ld_destroy( GtkObject *o, gpointer ud );
static void ld_cancel_check( GnomeDruid *gd, LoanDruidData *ldd );
static void ld_prm_type_change( GtkButton *b, gpointer ud );
static void ld_prm_type_changed( GtkWidget *w, gint index, gpointer ud );
static void ld_escrow_toggle( GtkToggleButton *tb, gpointer ud );
static void ld_opt_toggled( GtkToggleButton *tb, gpointer ud );
static void ld_opt_consistency( GtkToggleButton *tb, gpointer ud );
static void ld_escrow_tog( GtkToggleButton *tb, gpointer ud );
static void ld_escrow_toggled( GtkToggleButton *tb, gpointer ud );
static void ld_pay_freq_toggle( GtkToggleButton *tb, gpointer ud );
static gboolean ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static void ld_info_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static gboolean ld_opts_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static gboolean ld_opts_tran( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static void ld_opts_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static gboolean ld_rep_next ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static void ld_rep_prep ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static gboolean ld_rep_back ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static gboolean ld_pay_next ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static void ld_pay_prep ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static gboolean ld_pay_back ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static void ld_fin_prep ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static gboolean ld_fin_back ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
static void ld_fin_fin ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud );
struct LoanDruidData_*
gnc_ui_sx_loan_druid_create()
{
static struct {
char *pageName;
gboolean (*nextFn)();
void (*prepFn)();
gboolean (*backFn)();
void (*finishFn)();
/* cancel is handled by the druid itself. */
} DRUID_HANDLERS[] = {
{ PG_INFO, ld_info_save, ld_info_prep, ld_info_save, NULL },
{ PG_OPTS, ld_opts_next, ld_opts_prep, NULL, NULL },
{ PG_REPAYMENT, ld_rep_next, ld_rep_prep },
{ PG_PAYMENT, ld_pay_next, ld_pay_prep, ld_pay_back, NULL },
{ PG_FINISH, NULL, NULL, ld_fin_back, NULL },
{ NULL }
};
int i;
LoanDruidData *ldd;
@ -298,11 +308,11 @@ gnc_ui_sx_loan_druid_create()
int left, right, top, bottom;
} gas_data[] = {
{ &ldd->prmAccountGAS, ldd->prmTable, 1, 4, 0, 1 },
{ &ldd->repAssetsFromGAS, ldd->repTable, 1, 2, 2, 3 },
{ &ldd->repAssetsFromGAS, ldd->repTable, 1, 4, 2, 3 },
{ &ldd->repPrincToGAS, ldd->repTable, 1, 2, 3, 4 },
{ &ldd->repIntToGAS, ldd->repTable, 1, 2, 4, 5 },
{ &ldd->repEscrowToGAS, ldd->repTable, 1, 2, 5, 6 },
{ &ldd->payAccountGAS, ldd->payTable, 1, 2, 2, 3 },
{ &ldd->repIntToGAS, ldd->repTable, 3, 4, 3, 4 },
{ &ldd->payAcctFromGAS, ldd->payTable, 1, 2, 2, 3 },
{ &ldd->payAcctToGAS, ldd->payTable, 3, 4, 2, 3 },
{ NULL }
};
@ -334,9 +344,24 @@ gnc_ui_sx_loan_druid_create()
}
}
gtk_widget_set_sensitive( ldd->prmVarFrame, FALSE );
gtk_signal_connect( GTK_OBJECT(ldd->prmType), "clicked",
GTK_SIGNAL_FUNC(ld_prm_type_change), (gpointer)ldd );
gtk_widget_set_sensitive( GTK_WIDGET(ldd->prmVarFrame), FALSE );
{
GtkAlignment *a;
GNCOptionInfo typeOptInfo[] = {
{ "Fixed", "A Fixed-Rate loan", ld_prm_type_changed, ldd },
{ "3/1", "A 3/1 ARM", ld_prm_type_changed, ldd },
{ "5/1", "A 5/1 ARM", ld_prm_type_changed, ldd },
{ "7/1", "A 7/1 ARM", ld_prm_type_changed, ldd },
{ "10/1", "A 10/1 ARM", ld_prm_type_changed, ldd },
};
ldd->prmType =
GTK_OPTION_MENU( gnc_build_option_menu( typeOptInfo, 5 ) );
a = GTK_ALIGNMENT( gtk_alignment_new( 0.0, 0.5, 0.25, 1.0 ) );
gtk_container_add( GTK_CONTAINER(a), GTK_WIDGET(ldd->prmType) );
gtk_table_attach( ldd->prmTable, GTK_WIDGET(a),
3, 4, 2, 3,
0, 0, 2, 2 );
}
{
GtkAdjustment *a;
@ -365,6 +390,13 @@ gnc_ui_sx_loan_druid_create()
gnc_option_menu_init( GTK_WIDGET(ldd->prmLengthType) );
gnc_option_menu_init( GTK_WIDGET(ldd->repRemainderOpt) );
gtk_signal_connect( GTK_OBJECT(ldd->optEscrowCb), "toggled",
GTK_SIGNAL_FUNC(ld_escrow_toggle), ldd );
gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), FALSE );
ldd->optEscrowGAS = GNC_ACCOUNT_SEL(gnc_account_sel_new());
gtk_container_add( GTK_CONTAINER(ldd->optEscrowHBox),
GTK_WIDGET(ldd->optEscrowGAS) );
/* FIXME : too deep, factor out. */
{
/* . Each RepayOpt gets an entry in the optContainer.
@ -387,31 +419,39 @@ gnc_ui_sx_loan_druid_create()
vb = GTK_VBOX(gtk_vbox_new( FALSE, OPT_VBOX_SPACING ));
/* Add payment checkbox. */
g_string_sprintf( str, "... pay \"%s\"?", rouid->optData->name );
g_string_sprintf( str, "... pay \"%s\"?",
rouid->optData->name );
rouid->optCb =
GTK_CHECK_BUTTON(gtk_check_button_new_with_label( str->str ));
gtk_box_pack_start( GTK_BOX(vb), GTK_WIDGET(rouid->optCb),
GTK_CHECK_BUTTON(
gtk_check_button_new_with_label(
str->str ));
gtk_box_pack_start( GTK_BOX(vb),
GTK_WIDGET(rouid->optCb),
FALSE, FALSE, 2 );
rouid->escrowCb =
GTK_CHECK_BUTTON(gtk_check_button_new_with_label( _("via Escrow account?") ));
gtk_widget_set_sensitive( GTK_WIDGET(rouid->escrowCb), FALSE );
subOptAlign = GTK_ALIGNMENT(gtk_alignment_new( 0.5, 0.5, 0.75, 1.0 ));
GTK_CHECK_BUTTON(
gtk_check_button_new_with_label(
_("via Escrow account?") ));
gtk_widget_set_sensitive(
GTK_WIDGET(rouid->escrowCb),
FALSE );
subOptAlign =
GTK_ALIGNMENT(
gtk_alignment_new(
0.5, 0.5, 0.75, 1.0 ));
gtk_container_add( GTK_CONTAINER(subOptAlign),
GTK_WIDGET(rouid->escrowCb) );
gtk_box_pack_start( GTK_BOX(vb), GTK_WIDGET(subOptAlign),
FALSE, FALSE, 2 );
gtk_signal_connect( GTK_OBJECT( rouid->optCb ),
"toggled",
gtk_signal_connect( GTK_OBJECT( rouid->optCb ), "toggled",
GTK_SIGNAL_FUNC(ld_opt_toggled),
(gpointer)rouid );
gtk_signal_connect( GTK_OBJECT( rouid->optCb ),
"toggled",
gtk_signal_connect( GTK_OBJECT( rouid->optCb ), "toggled",
GTK_SIGNAL_FUNC(ld_opt_consistency),
(gpointer)rouid->escrowCb );
gtk_signal_connect( GTK_OBJECT( rouid->escrowCb ),
"toggled",
GTK_SIGNAL_FUNC(ld_escrow_tog),
(gpointer)rouid );
gtk_signal_connect( GTK_OBJECT( rouid->escrowCb ), "toggled",
GTK_SIGNAL_FUNC(ld_escrow_toggled),
(gpointer)rouid );
optAlign = GTK_ALIGNMENT(gtk_alignment_new( 0.5, 0.5, 0.75, 1.0 ));
@ -445,14 +485,22 @@ gnc_ui_sx_loan_druid_create()
GTK_WIDGET(ldd->payGncFreq) );
}
gnc_register_gui_component( DIALOG_LOAN_DRUID_CM_CLASS,
NULL, /* no refresh handler */
(GNCComponentCloseHandler*)ld_close_handler,
ldd );
gtk_signal_connect( GTK_OBJECT(ldd->dialog), "destroy",
GTK_SIGNAL_FUNC(ld_destroy),
ldd );
{
static struct {
char *pageName;
gboolean (*nextFn)();
void (*prepFn)();
gboolean (*backFn)();
void (*finishFn)();
/* cancel is handled by the druid itself. */
} DRUID_HANDLERS[] = {
{ PG_INFO, ld_info_save, ld_info_prep, ld_info_save, NULL },
{ PG_OPTS, ld_opts_tran, ld_opts_prep, ld_opts_tran, NULL },
{ PG_REPAYMENT, ld_rep_next, ld_rep_prep, ld_rep_back },
{ PG_PAYMENT, ld_pay_next, ld_pay_prep, ld_pay_back, NULL },
{ PG_FINISH, NULL, ld_fin_prep, ld_fin_back, ld_fin_fin },
{ NULL }
};
/* setup page-transition handlers */
/* setup druid-global handler for cancel */
@ -492,6 +540,16 @@ gnc_ui_sx_loan_druid_create()
ldd);
}
}
}
gnc_register_gui_component( DIALOG_LOAN_DRUID_CM_CLASS,
NULL, /* no refresh handler */
(GNCComponentCloseHandler)ld_close_handler,
ldd );
gtk_signal_connect( GTK_OBJECT(ldd->dialog), "destroy",
GTK_SIGNAL_FUNC(ld_destroy),
ldd );
gtk_widget_show_all( ldd->dialog );
return ldd;
@ -515,6 +573,12 @@ gnc_loan_druid_data_init( LoanDruidData *ldd )
ldd->ld.varStartDate = g_date_new();
g_date_set_time( ldd->ld.startDate, time(NULL) );
ldd->ld.loanFreq = xaccFreqSpecMalloc( gnc_get_current_book() );
ldd->ld.repFreq = xaccFreqSpecMalloc( gnc_get_current_book() );
xaccFreqSpecSetMonthly( ldd->ld.repFreq, ldd->ld.startDate, 1 );
xaccFreqSpecSetUIType( ldd->ld.repFreq, UIFREQ_MONTHLY );
ldd->ld.repAmount = NULL;
ldd->ld.repStartDate = g_date_new();
ldd->ld.repayOptCount = optCount;
ldd->ld.repayOpts = g_new0( RepayOptData*, optCount );
/* copy all the default lines into the LDD */
@ -523,6 +587,8 @@ gnc_loan_druid_data_init( LoanDruidData *ldd )
g_assert( REPAY_DEFAULTS[i].name != NULL );
ldd->repayOptsUI[i] = g_new0( RepayOptUIData, 1 );
ldd->repayOptsUI[i]->ldd = ldd;
optData = ldd->ld.repayOpts[i]
= ldd->repayOptsUI[i]->optData
= g_new0( RepayOptData, 1 );
@ -555,8 +621,6 @@ gnc_loan_druid_get_widgets( LoanDruidData *ldd )
GET_CASTED_WIDGET( GTK_TABLE, PARAM_TABLE );
ldd->prmIrateSpin =
GET_CASTED_WIDGET( GTK_SPIN_BUTTON, IRATE_SPIN );
ldd->prmType =
GET_CASTED_WIDGET( GTK_OPTION_MENU, TYPE_OPT );
ldd->prmVarFrame =
GET_CASTED_WIDGET( GTK_FRAME, VAR_CONTAINER );
ldd->prmStartDateGDE =
@ -571,14 +635,16 @@ gnc_loan_druid_get_widgets( LoanDruidData *ldd )
/* opt = options */
ldd->optVBox =
GET_CASTED_WIDGET( GTK_VBOX, OPT_CONTAINER );
ldd->optEscrowCb =
GET_CASTED_WIDGET( GTK_CHECK_BUTTON, OPT_ESCROW );
ldd->optEscrowHBox =
GET_CASTED_WIDGET( GTK_HBOX, OPT_ESCROW_CONTAINER );
/* rep = repayment */
ldd->repTxnName =
GET_CASTED_WIDGET( GTK_ENTRY, TXN_NAME );
ldd->repTable =
GET_CASTED_WIDGET( GTK_TABLE, REPAY_TABLE );
ldd->repAmtGNE =
GET_CASTED_WIDGET( GNOME_NUMBER_ENTRY, AMOUNT_GNE );
ldd->repAmtEntry =
GET_CASTED_WIDGET( GTK_ENTRY, AMOUNT_ENTRY );
ldd->repRemainderOpt =
@ -644,13 +710,56 @@ ld_cancel_check( GnomeDruid *gd, LoanDruidData *ldd )
static
void
ld_prm_type_change( GtkButton *b, gpointer ud )
ld_prm_type_changed( GtkWidget *w, gint index, gpointer ud )
{
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
gtk_widget_set_sensitive( ldd->prmVarFrame,
gnc_option_menu_get_active( ldd->prmType ) );
gtk_widget_set_sensitive( GTK_WIDGET(ldd->prmVarFrame),
index != FIXED );
}
static
void
ld_escrow_toggle( GtkToggleButton *tb, gpointer ud )
{
int i;
gboolean newState;
RepayOptUIData *rouid;
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
newState = gtk_toggle_button_get_active(tb);
gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), newState );
/* deal with escrow options. */
for ( i=0; i<ldd->ld.repayOptCount; i++ ) {
rouid = ldd->repayOptsUI[i];
/* If we're going off, then uncheck and desensitize all escrow opts. */
/* If we're going on, then sensitize all escrow opts. */
/* prevent the toggle handler from running and "trashing" the
* state of the throughEscrowP selection */
gtk_signal_handler_block_by_func( GTK_OBJECT(rouid->escrowCb),
GTK_SIGNAL_FUNC(ld_escrow_toggled),
rouid );
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(rouid->escrowCb),
newState
&& gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rouid->optCb) )
&& rouid->optData->throughEscrowP );
gtk_widget_set_sensitive(
GTK_WIDGET(rouid->escrowCb),
newState
&& gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rouid->optCb) ) );
gtk_signal_handler_unblock_by_func( GTK_OBJECT(rouid->escrowCb),
GTK_SIGNAL_FUNC(ld_escrow_toggled),
rouid );
if ( newState ) {
rouid->optData->from = ldd->ld.escrowAcct;
} else {
rouid->optData->from = NULL;
}
}
}
static
@ -668,20 +777,25 @@ void
ld_opt_consistency( GtkToggleButton *tb, gpointer ud )
{
GtkToggleButton *escrowCb;
RepayOptUIData *rouid;
escrowCb = GTK_TOGGLE_BUTTON(ud);
rouid = (RepayOptUIData*)ud;
escrowCb = GTK_TOGGLE_BUTTON(rouid->escrowCb);
/* make sure the escrow option is only selected if we're active. */
gtk_toggle_button_set_state( escrowCb,
gtk_toggle_button_get_active(escrowCb)
& gtk_toggle_button_get_active(tb) );
/* make sure the escrow option is only sensitive if we're active. */
rouid->optData->throughEscrowP
&& gtk_toggle_button_get_active(tb) );
/* make sure the escrow option is only sensitive if we're active, and
* the escrow account is enabled */
gtk_widget_set_sensitive( GTK_WIDGET(escrowCb),
gtk_toggle_button_get_active(tb) );
gtk_toggle_button_get_active(tb)
&& gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(rouid->ldd->optEscrowCb)) );
}
static
void
ld_escrow_tog( GtkToggleButton *tb, gpointer ud )
ld_escrow_toggled( GtkToggleButton *tb, gpointer ud )
{
RepayOptUIData *rouid;
@ -693,27 +807,15 @@ static
gboolean
ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
{
gchar *txt;
float amt;
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
/* FIXME: account */
ldd->ld.principal = gnc_amount_edit_get_amount( ldd->prmOrigPrincGAE );
#if 0
txt = gtk_editable_get_chars( GTK_EDITABLE(ldd->prmOrigPrincEntry),
0, -1 );
amt = -1.0;
amt = (float)strtod( txt, NULL );
if ( amt < 0 ) {
gnc_error_dialog( _("The original principal must "
"be a valid number.") );
return TRUE;
ldd->ld.primaryAcct = gnc_account_sel_get_account( ldd->prmAccountGAS );
if ( ! ldd->ld.repPriAcct ) {
ldd->ld.repPriAcct = ldd->ld.primaryAcct;
}
ldd->ld.principal = amt;
g_free( txt );
#endif /* 0 */
ldd->ld.principal = gnc_amount_edit_get_amount( ldd->prmOrigPrincGAE );
ldd->ld.interestRate =
gtk_spin_button_get_value_as_float( ldd->prmIrateSpin );
ldd->ld.type = gnc_option_menu_get_active( GTK_WIDGET(ldd->prmType) );
@ -731,7 +833,9 @@ ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
tmpTT = gnome_date_edit_get_date( ldd->prmStartDateGDE );
tmpTm = localtime( &tmpTT );
g_date_set_dmy( ldd->ld.startDate,
1, (tmpTm->tm_mon+1), tmpTm->tm_mday );
tmpTm->tm_mday,
(tmpTm->tm_mon+1),
(1900 + tmpTm->tm_year) );
}
/* len / periods */
@ -754,17 +858,7 @@ ld_info_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
/* FIXME: account. */
gnc_amount_edit_set_amount( ldd->prmOrigPrincGAE, ldd->ld.principal );
#if 0
{
GString *str;
str = g_string_sized_new( 16 );
g_string_sprintf( str, "%0.2f", ldd->principal );
gtk_entry_set_text( ldd->prmOrigPrincEntry, str->str );
g_string_free( str, TRUE );
}
#endif /* 0 */
gtk_spin_button_set_value( ldd->prmIrateSpin, ldd->ld.interestRate );
gtk_option_menu_set_history( ldd->prmType, ldd->ld.type );
if ( ldd->ld.type != FIXED ) {
@ -787,20 +881,29 @@ ld_info_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
/* length: total and remaining */
{
// prmLengthSpin
gtk_spin_button_set_value( ldd->prmLengthSpin, ldd->ld.numPer );
// prmLengthType
gtk_option_menu_set_history( ldd->prmLengthType, ldd->ld.perSize );
// prmRemainSpin
gtk_spin_button_set_value( ldd->prmRemainSpin, ldd->ld.numPerRemain );
}
}
static
gboolean
ld_opts_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
void
ld_opts_save_state( LoanDruidData *ldd )
{
/* FIXME: do anything here? */
if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb) ) ) {
ldd->ld.escrowAcct =
gnc_account_sel_get_account( ldd->optEscrowGAS );
} else {
ldd->ld.escrowAcct = NULL;
}
}
static
gboolean
ld_opts_tran( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
{
ld_opts_save_state( (LoanDruidData*)ud );
return FALSE;
}
@ -808,7 +911,66 @@ static
void
ld_opts_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
{
/* FIXME: setup the options */
int i;
RepayOptUIData *rouid;
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
if ( ldd->ld.escrowAcct ) {
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb),
TRUE );
gnc_account_sel_set_account( ldd->optEscrowGAS, ldd->ld.escrowAcct );
}
for ( i=0; i<ldd->ld.repayOptCount; i++ ) {
rouid = ldd->repayOptsUI[i];
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(rouid->optCb),
rouid->optData->enabled );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(rouid->escrowCb),
rouid->optData->throughEscrowP
&& rouid->optData->enabled
&& ldd->ld.escrowAcct );
gtk_widget_set_sensitive( GTK_WIDGET(rouid->escrowCb),
rouid->optData->enabled
&& ldd->ld.escrowAcct );
}
}
static
void
ld_rep_save( LoanDruidData *ldd )
{
int i;
if ( ldd->ld.repMemo )
g_free( ldd->ld.repMemo );
ldd->ld.repMemo =
gtk_editable_get_chars( GTK_EDITABLE(ldd->repTxnName), 0, -1 );
if ( ldd->ld.repAmount )
g_free( ldd->ld.repAmount );
ldd->ld.repAmount =
gtk_editable_get_chars( GTK_EDITABLE(ldd->repAmtEntry), 0, -1 );
ldd->ld.repFromAcct =
gnc_account_sel_get_account( ldd->repAssetsFromGAS );
ldd->ld.repPriAcct =
gnc_account_sel_get_account( ldd->repPrincToGAS );
ldd->ld.repIntAcct =
gnc_account_sel_get_account( ldd->repIntToGAS );
ldd->ld.remainderChoice =
gnc_option_menu_get_active( GTK_WIDGET(ldd->repRemainderOpt) );
gnc_frequency_save_state( ldd->repGncFreq,
ldd->ld.repFreq,
ldd->ld.repStartDate );
/* Set the 'from' accounts of the various options to be the
* Assets-From account, if they're not already something else. */
for ( i=0; i<ldd->ld.repayOptCount; i++ ) {
RepayOptData *rod = ldd->ld.repayOpts[i];
if ( ! rod->from ) {
rod->from = ldd->ld.repFromAcct;
}
}
}
static
@ -818,6 +980,9 @@ ld_rep_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
ld_rep_save( ldd );
if ( (ldd->currentIdx < 0)
|| (ldd->currentIdx >= ldd->ld.repayOptCount)
|| !ldd->ld.repayOpts[ldd->currentIdx]->enabled ) {
@ -839,11 +1004,56 @@ ld_rep_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
return FALSE;
}
static
gboolean
ld_rep_back( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
{
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
ld_rep_save(ldd);
return FALSE;
}
static
void
ld_rep_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
{
/* do anything? */
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
if ( !ldd->ld.repAmount ) {
GString *str;
str = g_string_sized_new( 64 );
g_string_sprintfa( str, "pmt( %.4f / 12 : %d : %0.2f : 0 : 0 )",
(ldd->ld.interestRate / 100),
ldd->ld.numPer,
gnc_numeric_to_double(ldd->ld.principal) );
ldd->ld.repAmount = str->str;
g_string_free( str, FALSE );
}
if ( ldd->ld.repMemo )
gtk_entry_set_text( ldd->repTxnName, ldd->ld.repMemo );
if ( ldd->ld.repAmount )
gtk_entry_set_text( ldd->repAmtEntry, ldd->ld.repAmount );
gnc_account_sel_set_account( ldd->repAssetsFromGAS,
ldd->ld.repFromAcct );
gnc_account_sel_set_account( ldd->repPrincToGAS,
ldd->ld.repPriAcct );
gnc_account_sel_set_account( ldd->repIntToGAS,
ldd->ld.repIntAcct );
gtk_option_menu_set_history( ldd->repRemainderOpt,
ldd->ld.remainderChoice );
gnc_frequency_setup( ldd->repGncFreq,
ldd->ld.repFreq,
ldd->ld.repStartDate );
}
static
@ -870,8 +1080,8 @@ ld_pay_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
g_string_sprintf( str, "%0.2f", rod->amount );
gtk_entry_set_text( ldd->payAmtEntry, str->str );
gnc_account_sel_set_account( ldd->payAccountGAS,
rod->from );
gnc_account_sel_set_account( ldd->payAcctFromGAS, rod->from );
gnc_account_sel_set_account( ldd->payAcctToGAS, rod->to );
uniq = (rod->fs != NULL);
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqPartRb),
@ -912,7 +1122,8 @@ ld_pay_save_current( LoanDruidData *ldd )
rod->amount = (float)strtod( tmpStr, NULL );
g_free( tmpStr );
rod->from = gnc_account_sel_get_account( ldd->payAccountGAS );
rod->from = gnc_account_sel_get_account( ldd->payAcctFromGAS );
rod->to = gnc_account_sel_get_account( ldd->payAcctToGAS );
/* if ( rb toggled )
* ensure freqspec/startdate setup
@ -1035,6 +1246,257 @@ ld_pay_freq_toggle( GtkToggleButton *tb, gpointer ud )
g_assert( ldd->currentIdx >= 0 );
g_assert( ldd->currentIdx <= ldd->ld.repayOptCount );
uniq = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb) );
uniq = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb) );
gtk_widget_set_sensitive( GTK_WIDGET(ldd->payFreqAlign), uniq );
if ( uniq ) {
RepayOptData *rod;
rod = ldd->ld.repayOpts[ ldd->currentIdx ];
if ( rod->fs == NULL ) {
rod->fs = xaccFreqSpecMalloc( gnc_get_current_book() );
xaccFreqSpecSetMonthly( rod->fs, ldd->ld.startDate, 1 );
xaccFreqSpecSetUIType( rod->fs, UIFREQ_MONTHLY );
}
if ( rod->startDate == NULL ) {
rod->startDate = g_date_new();
*rod->startDate = *ldd->ld.startDate;
}
gnc_frequency_setup( ldd->payGncFreq,
rod->fs, rod->startDate );
}
}
static
void
ld_fin_prep ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
{
/* FIXME? */
}
static
void
ld_free_ttsi( gpointer data, gpointer ud )
{
gnc_ttsplitinfo_free( (TTSplitInfo*)data );
}
static
void
ld_gnc_ttinfo_free( gpointer data, gpointer ud )
{
gnc_ttinfo_free( (TTInfo*)data );
}
static
void
ld_fin_fin ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
{
LoanDruidData *ldd;
int i;
TTInfo *tti;
TTSplitInfo *ttsi;
RepayOptData *rod;
SchedXaction *tmpSX;
GList *repTTList;
GList *repSplits;
gchar *tmpStr;
GString *repAssetsDebitFormula, *tmpGS;
GList *sxList;
ldd = (LoanDruidData*)ud;
/* Create a string for the Asset-account debit, which we will build
* up in the processing of the LoanData and Options. */
repAssetsDebitFormula = g_string_sized_new( 64 );
repTTList = NULL;
/* first, start to deal with the repayment uber-SX */
{
repSplits = NULL;
/* Just add the repayment amount to a string for the moment;
* create the split out of it after we've processed the
* options [and gotten their contributions to the asset debit
* formula]. */
g_string_sprintf( repAssetsDebitFormula, ldd->ld.repAmount );
/* Principal credit */
ttsi = gnc_ttsplitinfo_malloc();
gnc_ttsplitinfo_set_memo( ttsi, "Repayment - Principal Portion" );
tmpStr = xaccAccountGetFullName( ldd->ld.repPriAcct,
gnc_get_account_separator() );
g_free( tmpStr );
gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repPriAcct );
tmpGS = g_string_sized_new( 64 );
g_string_sprintf( tmpGS, "ppmt( %.4f / 12 : i : %d : %0.2f : 0 : 0 )",
(ldd->ld.interestRate / 100),
ldd->ld.numPer,
gnc_numeric_to_double(ldd->ld.principal));
gnc_ttsplitinfo_set_debit_formula( ttsi, tmpGS->str );
g_string_free( tmpGS, FALSE );
repSplits = g_list_append( repSplits, ttsi );
/* Interest credit */
ttsi = gnc_ttsplitinfo_malloc();
gnc_ttsplitinfo_set_memo( ttsi, "Repayment - Interest Portion" );
tmpStr = xaccAccountGetFullName( ldd->ld.repIntAcct,
gnc_get_account_separator() );
g_free( tmpStr );
gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repIntAcct );
tmpGS = g_string_sized_new( 64 );
g_string_sprintf( tmpGS, "ipmt( %.4f / 12 : i : %d : %0.2f : 0 : 0 )",
(ldd->ld.interestRate / 100),
ldd->ld.numPer,
gnc_numeric_to_double( ldd->ld.principal ) );
gnc_ttsplitinfo_set_debit_formula( ttsi, tmpGS->str );
g_string_free( tmpGS, FALSE );
repSplits = g_list_append( repSplits, ttsi );
}
/* Process the options. */
for ( i=0; i<ldd->ld.repayOptCount; i++ ) {
Account *fromAcct;
GList *optSplits;
GList *optTTList;
optSplits = NULL;
optTTList = NULL;
rod = ldd->ld.repayOpts[i];
if ( !rod->enabled )
continue;
fromAcct = rod->from;
if ( rod->throughEscrowP ) {
GString *amt = g_string_sized_new( 5 );
g_string_sprintf( amt, "%0.2f", rod->amount );
/* Add assets -> escrow Splits. */
g_string_sprintfa( repAssetsDebitFormula, " + %s", amt->str );
ttsi = gnc_ttsplitinfo_malloc();
gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo );
gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct );
gnc_ttsplitinfo_set_debit_formula( ttsi, amt->str );
repSplits = g_list_append( repSplits, ttsi );
g_string_free( amt, TRUE );
fromAcct = ldd->ld.escrowAcct;
}
ttsi = gnc_ttsplitinfo_malloc();
gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo );
gnc_ttsplitinfo_set_account( ttsi, fromAcct );
tmpStr = xaccAccountGetFullName( fromAcct,
gnc_get_account_separator() );
g_free( tmpStr );
{
GString *amt = g_string_sized_new(5);
g_string_sprintf( amt, "%0.2f", rod->amount );
gnc_ttsplitinfo_set_credit_formula( ttsi, amt->str );
g_string_free( amt, TRUE );
}
optSplits = g_list_append( optSplits, ttsi );
ttsi = gnc_ttsplitinfo_malloc();
gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo );
gnc_ttsplitinfo_set_account( ttsi, rod->to );
tmpStr = xaccAccountGetFullName( rod->to,
gnc_get_account_separator() );
g_free( tmpStr );
{
GString *amt = g_string_sized_new( 5 );
g_string_sprintf( amt, "%0.2f", rod->amount );
gnc_ttsplitinfo_set_debit_formula( ttsi, amt->str );
g_string_free( amt, TRUE );
}
optSplits = g_list_append( optSplits, ttsi );
tti = gnc_ttinfo_malloc();
gnc_ttinfo_set_description( tti, ldd->ld.repMemo );
gnc_ttinfo_set_template_splits( tti, optSplits );
/* we're no longer responsible for this list. */
optSplits = NULL;
if ( rod->fs ) {
GList *ttList;
ttList = NULL;
/* Create new SX with given FreqSpec */
ttList = g_list_append( ttList, tti );
tmpSX = xaccSchedXactionMalloc( gnc_get_current_book() );
/* FIXME? Get name from Liability/LoanAccount name? */
xaccSchedXactionSetName( tmpSX, ldd->ld.repMemo );
xaccSchedXactionSetFreqSpec( tmpSX, rod->fs );
xaccSchedXactionSetStartDate( tmpSX, rod->startDate );
xaccSchedXactionSetLastOccurDate( tmpSX, rod->startDate );
/* FIXME ... what are these values? */
xaccSchedXactionSetNumOccur( tmpSX, ldd->ld.numPer );
xaccSchedXactionSetRemOccur( tmpSX, ldd->ld.numPerRemain );
xaccSchedXactionSetTemplateTrans( tmpSX, ttList,
gnc_get_current_book() );
sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
sxList = g_list_append( sxList, tmpSX );
gnc_book_set_schedxactions( gnc_get_current_book(), sxList );
gnc_ttinfo_free( tti );
g_list_free( ttList );
ttList = NULL;
} else {
/* Add transaction to existing repayment SX. */
repTTList = g_list_append( repTTList, tti );
}
}
/* Create repayment assets debit split. */
ttsi = gnc_ttsplitinfo_malloc();
tmpStr = xaccAccountGetFullName( ldd->ld.repPriAcct,
gnc_get_account_separator() );
g_free( tmpStr );
gnc_ttsplitinfo_set_memo( ttsi, ldd->ld.repMemo );
gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repFromAcct );
gnc_ttsplitinfo_set_credit_formula( ttsi, repAssetsDebitFormula->str );
repSplits = g_list_append( repSplits, ttsi );
tti = gnc_ttinfo_malloc();
gnc_ttinfo_set_description( tti, ldd->ld.repMemo );
gnc_ttinfo_set_template_splits( tti, repSplits );
/* we're no longer responsible for this list. */
repSplits = NULL;
repTTList = g_list_append( repTTList, tti );
/* Actually create the SX for the repayment. */
tmpSX = xaccSchedXactionMalloc( gnc_get_current_book() );
xaccSchedXactionSetName( tmpSX, ldd->ld.repMemo );
xaccSchedXactionSetStartDate( tmpSX, ldd->ld.repStartDate );
xaccSchedXactionSetLastOccurDate( tmpSX, ldd->ld.repStartDate );
xaccSchedXactionSetFreqSpec( tmpSX, ldd->ld.repFreq );
/* FIXME: we should compare these values with the user-specified
* repayment frequency. */
xaccSchedXactionSetNumOccur( tmpSX, ldd->ld.numPer );
xaccSchedXactionSetRemOccur( tmpSX, ldd->ld.numPerRemain );
xaccSchedXactionSetTemplateTrans( tmpSX, repTTList,
gnc_get_current_book() );
gnc_sx_set_instance_count( tmpSX,
ldd->ld.numPer - ldd->ld.numPerRemain + 1 );
sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
sxList = g_list_append( sxList, tmpSX );
gnc_book_set_schedxactions( gnc_get_current_book(), sxList );
g_list_foreach( repTTList, ld_gnc_ttinfo_free, NULL );
g_list_free( repTTList );
repTTList = NULL;
g_string_free( repAssetsDebitFormula, TRUE );
ld_close_handler( ldd );
}

File diff suppressed because it is too large Load Diff

View File

@ -916,14 +916,14 @@ gnc_main_window_create_menus(GNCMDIInfo * maininfo)
static GnomeUIInfo gnc_sched_xaction_tools_submenu_template[] =
{
{ GNOME_APP_UI_ITEM,
N_("List and Editor"),
N_("_List and Editor"),
N_("The list of Scheduled Transactions"),
gnc_main_window_sched_xaction_cb, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
0, 0, NULL
},
{ GNOME_APP_UI_ITEM,
N_("Since Last Run..."),
N_("_Since Last Run..."),
N_("Create Scheduled Transactions since the last time run."),
gnc_main_window_sched_xaction_slr_cb, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
@ -931,7 +931,7 @@ gnc_main_window_create_menus(GNCMDIInfo * maininfo)
},
GNOMEUIINFO_SEPARATOR,
{ GNOME_APP_UI_ITEM,
N_( "Mortgage/Loan Repayment Setup" ),
N_( "_Mortgage/Loan Repayment Setup" ),
N_( "Setup scheduled transactions for repayment of a loan" ),
gnc_main_window_sx_loan_druid_cb, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
@ -942,7 +942,7 @@ gnc_main_window_create_menus(GNCMDIInfo * maininfo)
static GnomeUIInfo gnc_actions_menu_template[] =
{
GNOMEUIINFO_SUBTREE( N_("Scheduled Transactions"),
GNOMEUIINFO_SUBTREE( N_("_Scheduled Transactions"),
gnc_sched_xaction_tools_submenu_template ),
GNOMEUIINFO_END
};

View File

@ -16,26 +16,37 @@
;; Boston, MA 02111-1307, USA gnu@gnu.org
;; Copyright 2002 Joshua Sled <jsled@asynchronous.org>
;; pretty literal copies of similar code from gnumeric-1.0.8
;;
;; pretty literal copies of similar code from gnumeric-1.0.8, except we want
;; positive values to be returned [as gnucash will handle the credit/debit
;; appropriately]
(define (gnc:ipmt rate nper per pv fv type)
(* rate
(define (gnc:ipmt rate per nper pv fv type)
(* -1 (* rate
(- 0 (calc-principal pv
(calc-pmt rate nper pv fv type)
rate (- per 1))
)
)
rate (- per 1)))
))
)
(define (gnc:ppmt rate nper per pv fv type)
(let ((pmt (calc-pmt rate nper pv fv type)))
(let ((ipmt (* rate
(- 0 (calc-principal pv pmt rate (- per 1))))))
(- pmt ipmt)))
(define (gnc:ppmt rate per nper pv fv type)
(let* ((pmt (calc-pmt rate nper pv fv type))
(ipmt (* rate
(calc-principal pv pmt rate (- per 1)))))
(* -1 (-
pmt
(* -1 ipmt))))
)
(define (gnc:pmt rate nper pv fv type)
(calc-pmt rate nper pv fv type))
(* -1 (calc-pmt rate nper pv fv type)))
(define (gnc:foobar val) val)
;;;;;
;; below: not-exposed/"private" functions, used by the "public" functions
;; above.
;;;;;
(define (calc-pmt rate nper pv fv type)
(let ((pvif (calc-pvif rate nper))