r20646 - gnucash/trunk/src/gnome - Bug #647532: Enter APR as interest rate in Loan Druid
Christian Stimming
cstim at code.gnucash.org
Sun May 15 15:21:12 EDT 2011
Author: cstim
Date: 2011-05-15 15:21:10 -0400 (Sun, 15 May 2011)
New Revision: 20646
Trac: http://svn.gnucash.org/trac/changeset/20646
Modified:
gnucash/trunk/src/gnome/druid-loan.c
gnucash/trunk/src/gnome/glade/sched-xact.glade
Log:
Bug #647532: Enter APR as interest rate in Loan Druid
Patch by Nick:
This patch allows the user to enter the APR for a loan rather than the simple
interest rate and then the druid will calculate the correct interest rate for
the scheduled transaction that it produces.
It includes a small change to the shed-xact.glade file which provides a
dropdown box to select the rate that has been entered and changes to
druid-loan.c which calculate the simple interest rate as the scheduled
transaction strings are generated.
Modified: gnucash/trunk/src/gnome/druid-loan.c
===================================================================
--- gnucash/trunk/src/gnome/druid-loan.c 2011-05-15 00:37:03 UTC (rev 20645)
+++ gnucash/trunk/src/gnome/druid-loan.c 2011-05-15 19:21:10 UTC (rev 20646)
@@ -61,6 +61,7 @@
# define PARAM_TABLE "param_table"
# define ORIG_PRINC_ENTRY "orig_princ_ent"
# define IRATE_SPIN "irate_spin"
+# define IRATE_TYPE_COMBOBOX "irate_type_combobox"
# define TYPE_COMBOBOX "type_combobox"
# define VAR_CONTAINER "type_freq_frame"
# define LENGTH_SPIN "len_spin"
@@ -198,6 +199,16 @@
GNC_MONTHS = 0,
GNC_YEARS
} PeriodSize;
+/*type of interest rate entered*/
+typedef enum
+{
+ GNC_IRATE_SIMPLE,
+ GNC_IRATE_APR_DAILY,
+ GNC_IRATE_APR_WEEKLY,
+ GNC_IRATE_APR_MONTHLY,
+ GNC_IRATE_APR_QUARTERLY,
+ GNC_IRATE_APR_ANNUALLY
+} IRateType;
/**
* A transient struct used to collate the GDate and the gnc_numeric row-data
@@ -218,6 +229,7 @@
Account *primaryAcct;
gnc_numeric principal;
float interestRate;
+ IRateType rateType;
LoanType type;
GList *loan_schedule;
GDate *startDate;
@@ -277,6 +289,7 @@
GtkSpinButton *prmLengthSpin;
GtkComboBox *prmLengthType;
GtkSpinButton *prmRemainSpin;
+ GtkComboBox *prmIrateType;
/* opt = options */
GtkVBox *optVBox;
@@ -411,6 +424,7 @@
gconstpointer crit );
static void ld_create_sx_from_tcSX( LoanDruidData *ldd, toCreateSX *tcSX );
static void ld_tcSX_free( gpointer data, gpointer user_data );
+static float ld_apr_to_simple_formula (float rate, float compounding_periods);
struct LoanDruidData_*
gnc_ui_sx_loan_druid_create(void)
@@ -890,6 +904,8 @@
GET_CASTED_WIDGET( GTK_COMBO_BOX, LENGTH_OPT );
ldd->prmRemainSpin =
GET_CASTED_WIDGET( GTK_SPIN_BUTTON, REMAIN_SPIN );
+ ldd->prmIrateType =
+ GET_CASTED_WIDGET( GTK_COMBO_BOX, IRATE_TYPE_COMBOBOX );
/* opt = options */
ldd->optVBox =
@@ -947,46 +963,264 @@
}
+/* convert APR rate to simple rate based on formula r=q((1+i)^(1/q)-1) (r=interest rate, i=apr, q=compounding periods) */
+
+gfloat ld_apr_to_simple_formula (gfloat rate, gfloat compounding_periods)
+{
+ /* float percent_to_frac; - redundant */
+ gfloat simple_rate;
+ /* percent_to_frac= compounding_periods/100; - redundant */
+ simple_rate = compounding_periods * ((pow((1 + rate), (1 / compounding_periods))) - 1);
+ return (simple_rate);
+}
+
+
static
void
ld_get_pmt_formula( LoanDruidData *ldd, GString *gstr )
{
+ gint rate_case;
+ gfloat pass_thru_rate;
g_assert( ldd != NULL );
g_assert( gstr != NULL );
- g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )",
- (ldd->ld.interestRate / 100),
- 12.0,
- ( ldd->ld.numPer
- * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
- gnc_numeric_to_double(ldd->ld.principal) );
+ rate_case = ldd->ld.rateType;
+ pass_thru_rate = ldd->ld.interestRate / 100;
+ switch (rate_case)
+ {
+ case GNC_IRATE_SIMPLE:
+ {
+ g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )",
+ pass_thru_rate, 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal) );
+ }
+ break;
+ case GNC_IRATE_APR_DAILY:
+ {
+ g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 365),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal) );
+ }
+ break;
+ case GNC_IRATE_APR_WEEKLY:
+ {
+ g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 52),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal) );
+ }
+ break;
+ case GNC_IRATE_APR_MONTHLY:
+ {
+ g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 12),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal) );
+ }
+ break;
+ case GNC_IRATE_APR_QUARTERLY:
+ {
+ g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 4),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal) );
+ }
+ break;
+ case GNC_IRATE_APR_ANNUALLY:
+ {
+ g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 1),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal) );
+ }
+ break;
+ default:
+ g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )",
+ (ldd->ld.interestRate / 100),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal) );
+ break;
+ }
}
static
void
ld_get_ppmt_formula( LoanDruidData *ldd, GString *gstr )
{
+ gint rate_case;
+ gfloat pass_thru_rate;
g_assert( ldd != NULL );
g_assert( gstr != NULL );
- g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
- (ldd->ld.interestRate / 100),
- 12.0,
- ( ldd->ld.numPer
- * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
- gnc_numeric_to_double(ldd->ld.principal));
+ rate_case = ldd->ld.rateType;
+ pass_thru_rate = ldd->ld.interestRate / 100;
+ switch (rate_case)
+ {
+ case GNC_IRATE_SIMPLE:
+ {
+ g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ pass_thru_rate,
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_DAILY:
+ {
+ g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 365),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_WEEKLY:
+ {
+ g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 52),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_MONTHLY:
+ {
+ g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 12),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_QUARTERLY:
+ {
+ g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 4),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_ANNUALLY:
+ {
+ g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 1),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ default:
+ g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ (ldd->ld.interestRate / 100),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ break;
+ }
}
static
void
ld_get_ipmt_formula( LoanDruidData *ldd, GString *gstr )
{
+ gint rate_case;
+ gfloat pass_thru_rate;
g_assert( ldd != NULL );
g_assert( gstr != NULL );
- g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
- (ldd->ld.interestRate / 100),
- 12.0,
- ( ldd->ld.numPer
- * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
- gnc_numeric_to_double( ldd->ld.principal ) );
+ rate_case = ldd->ld.rateType;
+ pass_thru_rate = ldd->ld.interestRate / 100;
+ switch (rate_case)
+ {
+ case GNC_IRATE_SIMPLE:
+ {
+ g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ pass_thru_rate,
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_DAILY:
+ {
+ g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 365),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_WEEKLY:
+ {
+ g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 52),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_MONTHLY:
+ {
+ g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 12),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_QUARTERLY:
+ {
+ g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 4),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ case GNC_IRATE_APR_ANNUALLY:
+ {
+ g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ ld_apr_to_simple_formula(pass_thru_rate, 1),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ }
+ break;
+ default:
+ g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )",
+ (ldd->ld.interestRate / 100),
+ 12.0,
+ ( ldd->ld.numPer
+ * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1.,
+ gnc_numeric_to_double(ldd->ld.principal));
+ break;
+ }
}
static
@@ -1203,6 +1437,7 @@
}
ldd->ld.principal = gnc_amount_edit_get_amount( ldd->prmOrigPrincGAE );
ldd->ld.interestRate = gtk_spin_button_get_value( ldd->prmIrateSpin );
+ ldd->ld.rateType = gtk_combo_box_get_active (ldd->prmIrateType );
ldd->ld.type = gtk_combo_box_get_active( ldd->prmType );
if ( ldd->ld.type != GNC_FIXED )
{
@@ -1247,6 +1482,7 @@
ldd = (LoanDruidData*)ud;
gnc_amount_edit_set_amount( ldd->prmOrigPrincGAE, ldd->ld.principal );
gtk_spin_button_set_value( ldd->prmIrateSpin, ldd->ld.interestRate );
+ gtk_combo_box_set_active( ldd->prmIrateType, ldd ->ld.rateType );
gtk_combo_box_set_active( ldd->prmType, ldd->ld.type );
if ( ldd->ld.type != GNC_FIXED )
{
@@ -1446,6 +1682,7 @@
LoanDruidData *ldd;
GString *str;
+
ldd = (LoanDruidData*)ud;
if ( ldd->ld.repAmount )
@@ -1454,7 +1691,7 @@
}
str = g_string_sized_new( 64 );
- ld_get_pmt_formula( ldd, str );
+ ld_get_pmt_formula( ldd, str);
ldd->ld.repAmount = str->str;
g_string_free( str, FALSE );
Modified: gnucash/trunk/src/gnome/glade/sched-xact.glade
===================================================================
--- gnucash/trunk/src/gnome/glade/sched-xact.glade 2011-05-15 00:37:03 UTC (rev 20645)
+++ gnucash/trunk/src/gnome/glade/sched-xact.glade 2011-05-15 19:21:10 UTC (rev 20646)
@@ -1908,20 +1908,6 @@
<property name="column_spacing">5</property>
<property name="row_spacing">5</property>
<child>
- <widget class="GtkLabel" id="label847897">
- <property name="visible">True</property>
- <property name="xalign">1</property>
- <property name="label" translatable="yes">Interest Rate:</property>
- <property name="justify">center</property>
- </widget>
- <packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
<widget class="GtkLabel" id="label847899">
<property name="visible">True</property>
<property name="xalign">1</property>
@@ -2171,26 +2157,24 @@
</packing>
</child>
<child>
- <placeholder/>
+ <widget class="GtkComboBox" id="irate_type_combobox">
+ <property name="visible">True</property>
+ <property name="active">1</property>
+ <property name="items" translatable="yes">Interest Rate
+APR (Compounded Daily)
+APR (Compounded Weekly)
+APR (Compounded Monthly)
+APR (Compounded Quarterly)
+APR (Compounded Annually)
+</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</widget>
<packing>
<property name="position">0</property>
More information about the gnucash-changes
mailing list