diff --git a/src/doc/sx.rst b/src/doc/sx.rst index ce72b44bf8..95457b5ffe 100644 --- a/src/doc/sx.rst +++ b/src/doc/sx.rst @@ -105,7 +105,7 @@ TODO - [#] type+ui-type -> type - use Recurrence instead of FreqSpec -! - [ ] load druid +! - [x] load druid ! - [x] sx-from-trans, ! - [x] XML migration, handling - xml:freqSpec -> obj:Recurrence @@ -141,6 +141,10 @@ TODO - [x] More compact recurrenceListToString(...). - [ ] remove FreqSpec code - [ ] SX code + - [ ] engine + - [ ] backend + - [ ] gnc-frequency + - [ ] gnc-dense-cal-store - [x] src/gnome/druid-acct-period.c - gnc_frequency diff --git a/src/gnome/druid-loan.c b/src/gnome/druid-loan.c index 1f9bbe06d6..0d7db5945d 100644 --- a/src/gnome/druid-loan.c +++ b/src/gnome/druid-loan.c @@ -1,7 +1,7 @@ /********************************************************************\ * druid-loan.c : A Gnome Druid for setting up loan-repayment * * scheduled transactions. * - * Copyright (C) 2002 Joshua Sled * + * Copyright (C) 2002,2007 Joshua Sled * * Copyright (C) 2006 David Hampton * * * * This program is free software; you can redistribute it and/or * @@ -45,7 +45,6 @@ #include "gnc-component-manager.h" #include "dialog-utils.h" #include "Account.h" -#include "FreqSpec.h" #include "gnc-ui.h" #include "gnc-gdate-utils.h" #include "gnc-gui-query.h" @@ -141,8 +140,9 @@ typedef struct RepayOptData_ { Account *to; Account *from; /* If NULL { If throughEscrowP, then through escrowAcct }; * else: undefined. */ - FreqSpec *fs; /* If NULL, part of repayment; otherwise: defined - * here. */ + GList *schedule; + /* If NULL, part of repayment; otherwise: defined + * here. */ GDate *startDate; } RepayOptData; @@ -211,7 +211,7 @@ typedef struct LoanData_ { gnc_numeric principal; float interestRate; LoanType type; - FreqSpec *loanFreq; + GList *loan_schedule; GDate *startDate; GDate *varStartDate; int numPer; @@ -224,7 +224,7 @@ typedef struct LoanData_ { Account *repPriAcct; Account *repIntAcct; Account *escrowAcct; - FreqSpec *repFreq; + GList *repayment_schedule; GDate *repStartDate; int repayOptCount; @@ -322,8 +322,8 @@ typedef struct toCreateSX_ gchar *name; /** The start, last-occurred and end dates. */ GDate start, last, end; - /** The SX FreqSpec */ - FreqSpec *freq; + /** The SX schedule */ + GList *schedule; /** The current 'instance-num' count. */ gint instNum; /** The main/source transaction being created. */ @@ -800,10 +800,13 @@ gnc_loan_druid_data_init( LoanDruidData *ldd ) ldd->ld.startDate = g_date_new(); ldd->ld.varStartDate = g_date_new(); g_date_set_time_t( 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.loan_schedule= NULL; + ldd->ld.repayment_schedule = NULL; + { + Recurrence *r = g_new0(Recurrence, 1); + recurrenceSet(r, 1, PERIOD_MONTH, ldd->ld.startDate); + ldd->ld.repayment_schedule = g_list_append(ldd->ld.repayment_schedule, r); + } ldd->ld.repMemo = g_strdup( _("Loan") ); ldd->ld.repAmount = NULL; @@ -829,7 +832,7 @@ gnc_loan_druid_data_init( LoanDruidData *ldd ) optData->amount = 0.0; optData->throughEscrowP = REPAY_DEFAULTS[i].escrowDefault; optData->specSrcAcctP = REPAY_DEFAULTS[i].specSrcAcctDefault; - optData->fs = NULL; + optData->schedule = NULL; optData->startDate = NULL; } } @@ -986,7 +989,7 @@ ld_destroy( GtkObject *o, gpointer ud ) g_date_free( ldd->ld.startDate ); g_date_free( ldd->ld.varStartDate ); - xaccFreqSpecFree( ldd->ld.loanFreq ); + recurrenceListFree(&ldd->ld.loan_schedule); if ( ldd->ld.repMemo ) g_free( ldd->ld.repMemo ); @@ -1001,8 +1004,8 @@ ld_destroy( GtkObject *o, gpointer ud ) if ( rod->startDate ) g_date_free( rod->startDate ); - if ( rod->fs ) - xaccFreqSpecFree( rod->fs ); + if (rod->schedule != NULL) + recurrenceListFree(&rod->schedule); g_free( ldd->ld.repayOpts[i] ); g_free( ldd->repayOptsUI[i] ); @@ -1164,9 +1167,10 @@ ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) ldd->ld.interestRate = gtk_spin_button_get_value( ldd->prmIrateSpin ); ldd->ld.type = gtk_combo_box_get_active( ldd->prmType ); if ( ldd->ld.type != GNC_FIXED ) { - gnc_frequency_save_state( ldd->prmVarGncFreq, - ldd->ld.loanFreq, - ldd->ld.varStartDate ); + recurrenceListFree(&ldd->ld.loan_schedule); + gnc_frequency_save_to_recurrence(ldd->prmVarGncFreq, + &ldd->ld.loan_schedule, + ldd->ld.varStartDate); } /* start date */ @@ -1206,9 +1210,9 @@ ld_info_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) gtk_spin_button_set_value( ldd->prmIrateSpin, ldd->ld.interestRate ); gtk_combo_box_set_active( ldd->prmType, ldd->ld.type ); if ( ldd->ld.type != GNC_FIXED ) { - gnc_frequency_setup( ldd->prmVarGncFreq, - ldd->ld.loanFreq, - ldd->ld.varStartDate ); + gnc_frequency_setup_recurrence(ldd->prmVarGncFreq, + ldd->ld.loan_schedule, + ldd->ld.varStartDate); } /* start date */ @@ -1324,9 +1328,10 @@ ld_rep_save( LoanDruidData *ldd ) "\"interest\" account.") ); return TRUE; } - gnc_frequency_save_state( ldd->repGncFreq, - ldd->ld.repFreq, - ldd->ld.repStartDate ); + recurrenceListFree(&ldd->ld.repayment_schedule); + gnc_frequency_save_to_recurrence(ldd->repGncFreq, + &ldd->ld.repayment_schedule, + ldd->ld.repStartDate); /* Set the 'from' accounts of the various options to be the * Assets-From account, if they're not already something else. */ @@ -1411,9 +1416,9 @@ ld_rep_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) ldd->ld.repPriAcct ); gnc_account_sel_set_account( ldd->repIntToGAS, ldd->ld.repIntAcct ); - gnc_frequency_setup( ldd->repGncFreq, - ldd->ld.repFreq, - ldd->ld.repStartDate ); + gnc_frequency_setup_recurrence(ldd->repGncFreq, + ldd->ld.repayment_schedule, + ldd->ld.repStartDate); } static @@ -1477,7 +1482,7 @@ ld_pay_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) gnc_account_sel_set_account( ldd->payAcctToGAS, rod->to ); - uniq = (rod->fs != NULL); + uniq = (rod->schedule != NULL); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqPartRb), !uniq ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb), @@ -1485,8 +1490,7 @@ ld_pay_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) gtk_widget_set_sensitive( GTK_WIDGET(ldd->payFreqAlign), uniq ); if ( uniq ) { - gnc_frequency_setup( ldd->payGncFreq, - rod->fs, rod->startDate ); + gnc_frequency_setup_recurrence( ldd->payGncFreq, rod->schedule, rod->startDate ); } g_string_free( str, TRUE ); @@ -1548,22 +1552,20 @@ ld_pay_save_current( LoanDruidData *ldd ) */ /* neither of these should happen. */ - g_assert( ! (rod->fs && !rod->startDate) ); - g_assert( ! (!rod->fs && rod->startDate) ); + g_assert( ! (rod->schedule && !rod->startDate) ); + g_assert( ! (!rod->schedule && rod->startDate) ); if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb)) ) { - if ( rod->fs == NULL ) { - rod->fs = xaccFreqSpecMalloc( gnc_get_current_book() ); - } if ( rod->startDate == NULL ) { rod->startDate = g_date_new(); } - gnc_frequency_save_state( ldd->payGncFreq, - rod->fs, rod->startDate ); + recurrenceListFree(&rod->schedule); + gnc_frequency_save_to_recurrence(ldd->payGncFreq, + &rod->schedule, + rod->startDate); } else { - if ( rod->fs ) { - xaccFreqSpecFree( rod->fs ); - rod->fs = NULL; + if (rod->schedule) { + recurrenceListFree(&rod->schedule); } if ( rod->startDate ) { g_date_free( rod->startDate ); @@ -1655,17 +1657,18 @@ ld_pay_freq_toggle( GtkToggleButton *tb, gpointer ud ) 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->schedule == NULL ) { + Recurrence *r = g_new0(Recurrence, 1); + recurrenceSet(r, 1, PERIOD_MONTH, ldd->ld.startDate); + rod->schedule = g_list_append(rod->schedule, r); } if ( rod->startDate == NULL ) { rod->startDate = g_date_new(); *rod->startDate = *ldd->ld.startDate; } - gnc_frequency_setup( ldd->payGncFreq, - rod->fs, rod->startDate ); + gnc_frequency_setup_recurrence(ldd->payGncFreq, + rod->schedule, + rod->startDate); } } @@ -1898,51 +1901,28 @@ ld_com_fin( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) } -#if 0 -static -void -ld_gnc_ttinfo_free( gpointer data, gpointer ud ) +static int +ld_calc_sx_instance_num(GDate *start_date, GList *schedule) { - gnc_ttinfo_free( (TTInfo*)data ); -} -#endif + int instance_count; + GDate next_date, today; -static -int -ld_calc_current_instance_num( int monthsPassed, FreqSpec *fs ) -{ - float mult = 1.0; - UIFreqType uift; - uift = xaccFreqSpecGetUIType( fs ); - switch ( uift ) { - case UIFREQ_WEEKLY: - { - int wMult, dow; - xaccFreqSpecGetWeekly( fs, &wMult, &dow ); - mult = (4.0 / wMult); - } - break; - case UIFREQ_BI_WEEKLY: - case UIFREQ_SEMI_MONTHLY: - mult = 2.0; - break; - case UIFREQ_MONTHLY: - case UIFREQ_QUARTERLY: - case UIFREQ_TRI_ANUALLY: - case UIFREQ_SEMI_YEARLY: - case UIFREQ_YEARLY: - { - int mMult, dom, offset; - xaccFreqSpecGetMonthly( fs, &mMult, &dom, &offset ); - mult = ( 1.0 / mMult ); - } - break; - default: - PERR( "Wacky loan repayment frequency [%d]", uift ); - break; - } + g_date_clear(&next_date, 1); + g_date_clear(&today, 1); + g_date_set_time_t(&today, time(NULL)); + + if (g_date_compare(start_date, &today) > 0) + return 0; + + instance_count = -1; + do + { + instance_count++; + recurrenceListNextInstance(schedule, start_date, &next_date); + } + while (g_date_compare(&next_date, &today) < 0); - return floor( monthsPassed * mult ); + return instance_count; } static @@ -1986,7 +1966,7 @@ ld_create_sx_from_tcSX( LoanDruidData *ldd, toCreateSX *tcSX ) sx = xaccSchedXactionMalloc( gnc_get_current_book() ); xaccSchedXactionSetName( sx, tcSX->name ); - xaccSchedXactionSetFreqSpec( sx, tcSX->freq ); + gnc_sx_set_schedule(sx, tcSX->schedule); xaccSchedXactionSetStartDate( sx, &tcSX->start ); xaccSchedXactionSetLastOccurDate( sx, &tcSX->last ); xaccSchedXactionSetEndDate( sx, &tcSX->end ); @@ -2013,7 +1993,7 @@ ld_create_sx_from_tcSX( LoanDruidData *ldd, toCreateSX *tcSX ) /** * Does the work to setup the given toCreateSX structure for a specific * repayment. Note that if the RepayOptData doesn't specify a unique - * FreqSpec, the paymentSX and the tcSX parameters will be the same. + * schedule, the paymentSX and the tcSX parameters will be the same. **/ static void @@ -2255,7 +2235,7 @@ ld_create_sxes( LoanDruidData *ldd ) { /* The main loan-payment SX.*/ toCreateSX *paymentSX = NULL; - /* A GList of any other repayment SXes with different FreqSpecs. */ + /* A GList of any other repayment SXes with different schedule. */ GList *repaySXes = NULL; /* The currently-being-referenced toCreateSX. */ toCreateSX *tcSX; @@ -2273,7 +2253,7 @@ ld_create_sxes( LoanDruidData *ldd ) paymentSX->end = *ldd->ld.repStartDate; g_date_add_months( &paymentSX->end, ldd->ld.numMonRemain - 1); } - paymentSX->freq = ldd->ld.repFreq; + paymentSX->schedule = ldd->ld.repayment_schedule; /* Figure out the correct current instance-count for the txns in the * SX. */ paymentSX->instNum = @@ -2431,7 +2411,7 @@ ld_create_sxes( LoanDruidData *ldd ) continue; tcSX = paymentSX; - if ( rod->fs != NULL ) { + if ( rod->schedule != NULL ) { tcSX = g_new0( toCreateSX, 1 ); gstr = g_string_new( ldd->ld.repMemo ); g_string_append_printf( gstr, " - %s", @@ -2443,13 +2423,13 @@ ld_create_sxes( LoanDruidData *ldd ) tcSX->end = tcSX->last; g_date_add_months( &tcSX->end, ldd->ld.numMonRemain ); } - tcSX->freq = rod->fs; + tcSX->schedule = rod->schedule; /* So it won't get destroyed when the close the * Druid. */ - tcSX->instNum = ld_calc_current_instance_num( paymentSX->instNum, - rod->fs ); - rod->fs = NULL; - tcSX->mainTxn = gnc_ttinfo_malloc(); + tcSX->instNum = + ld_calc_sx_instance_num(&tcSX->start, rod->schedule); + rod->schedule = NULL; + tcSX->mainTxn = gnc_ttinfo_malloc(); gnc_ttinfo_set_currency( tcSX->mainTxn, gnc_default_currency() ); gnc_ttinfo_set_description( tcSX->mainTxn, @@ -2641,20 +2621,21 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) { GDate start, end; gnc_numeric *rowNumData; - GHashTable *schedule; + GHashTable *repayment_schedule; g_date_clear( &start, 1 ); g_date_clear( &end, 1 ); ld_get_loan_range( ldd, &start, &end ); - /* The schedule is a hash of GDates to row-of-gnc_numeric[N] data, - * where N is the number of columns as determined by the _prep - * function, and stored in LoanData::revNumPmts. */ - schedule = g_hash_table_new( g_date_hash, g_date_equals ); + /* The repayment_schedule is a hash of GDates to + * row-of-gnc_numeric[N] data, where N is the number of columns as + * determined by the _prep function, and stored in + * LoanData::revNumPmts. */ + repayment_schedule = g_hash_table_new( g_date_hash, g_date_equals ); /* Do the master repayment */ { - GDate curDate; + GDate curDate, nextDate; GString *pmtFormula, *ppmtFormula, *ipmtFormula; int i; GHashTable *ivar; @@ -2670,20 +2651,21 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) g_date_clear( &curDate, 1 ); curDate = start; g_date_subtract_days( &curDate, 1 ); - xaccFreqSpecGetNextInstance( ldd->ld.repFreq, - &curDate, &curDate ); + g_date_clear(&nextDate, 1); + recurrenceListNextInstance(ldd->ld.repayment_schedule, &curDate, &nextDate); for ( i=1; - g_date_valid( &curDate ) - && g_date_compare( &curDate, &end ) <= 0 ; + g_date_valid( &nextDate ) + && g_date_compare( &nextDate, &end ) <= 0 ; i++, - xaccFreqSpecGetNextInstance( ldd->ld.repFreq, - &curDate, &curDate ) ) + curDate = nextDate, + recurrenceListNextInstance(ldd->ld.repayment_schedule, + &curDate, &nextDate)) { gnc_numeric ival; gnc_numeric val; char *eloc; rowNumData = - (gnc_numeric*)g_hash_table_lookup( schedule, + (gnc_numeric*)g_hash_table_lookup( repayment_schedule, &curDate ); if ( rowNumData == NULL) { int j; @@ -2695,7 +2677,7 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) for ( j=0; jld.revNumPmts; j++ ) { rowNumData[j] = gnc_numeric_error( GNC_ERROR_ARG ); } - g_hash_table_insert( schedule, + g_hash_table_insert( repayment_schedule, (gpointer)dateKeyCopy, (gpointer)rowNumData ); } @@ -2740,32 +2722,35 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) /* Process any other enabled payments. */ { int i; - GDate curDate; - FreqSpec *fs; + GDate curDate, nextDate; + GList *schedule; for ( i=0; ild.repayOptCount; i++ ) { if ( ! ldd->ld.repayOpts[i]->enabled ) continue; - fs = ( ldd->ld.repayOpts[i]->fs != NULL - ? ldd->ld.repayOpts[i]->fs - : ldd->ld.repFreq ); + schedule + = ( ldd->ld.repayOpts[i]->schedule != NULL + ? ldd->ld.repayOpts[i]->schedule + : ldd->ld.repayment_schedule ); g_date_clear( &curDate, 1 ); curDate = start; g_date_subtract_days( &curDate, 1 ); - xaccFreqSpecGetNextInstance( fs, &curDate, &curDate ); - for ( ; g_date_valid( &curDate ) - && g_date_compare( &curDate, &end ) <= 0; - xaccFreqSpecGetNextInstance( - fs, &curDate, &curDate ) ) + g_date_clear(&nextDate, 1); + recurrenceListNextInstance(schedule, &curDate, &nextDate ); + for ( ; g_date_valid( &nextDate ) + && g_date_compare( &nextDate, &end ) <= 0; + curDate = nextDate, + recurrenceListNextInstance( + schedule, &curDate, &nextDate ) ) { gint gncn_how = GNC_DENOM_SIGFIGS(2) | GNC_RND_ROUND; gnc_numeric val; - rowNumData = (gnc_numeric*)g_hash_table_lookup( schedule, + rowNumData = (gnc_numeric*)g_hash_table_lookup( repayment_schedule, &curDate ); if ( rowNumData == NULL ) { int j; @@ -2777,7 +2762,7 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) for ( j=0; jld.revNumPmts; j++ ) { rowNumData[j] = gnc_numeric_error( GNC_ERROR_ARG ); } - g_hash_table_insert( schedule, + g_hash_table_insert( repayment_schedule, (gpointer)dateKeyCopy, (gpointer)rowNumData ); } @@ -2801,11 +2786,11 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) g_list_free( ldd->ld.revSchedule ); ldd->ld.revSchedule = NULL; } - g_hash_table_foreach( schedule, ld_rev_hash_to_list, + g_hash_table_foreach( repayment_schedule, ld_rev_hash_to_list, &ldd->ld.revSchedule ); - g_hash_table_foreach( schedule, ld_rev_hash_free_date_keys, + g_hash_table_foreach( repayment_schedule, ld_rev_hash_free_date_keys, NULL ); - g_hash_table_destroy( schedule ); + g_hash_table_destroy( repayment_schedule ); ldd->ld.revSchedule = g_list_sort( ldd->ld.revSchedule, (GCompareFunc)g_date_compare ); }