mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Merge T Edmunds's 'amortization-rounding' into maint.
This commit is contained in:
commit
aa53c23239
@ -12,13 +12,13 @@ enable_testing()
|
|||||||
|
|
||||||
# Version number of gnucash
|
# Version number of gnucash
|
||||||
set (GNUCASH_MAJOR_VERSION 3)
|
set (GNUCASH_MAJOR_VERSION 3)
|
||||||
set (GNUCASH_MINOR_VERSION 5)
|
set (GNUCASH_MINOR_VERSION 900)
|
||||||
set (VERSION "${GNUCASH_MAJOR_VERSION}.${GNUCASH_MINOR_VERSION}")
|
set (VERSION "${GNUCASH_MAJOR_VERSION}.${GNUCASH_MINOR_VERSION}")
|
||||||
set (GNUCASH_LATEST_STABLE_SERIES 3.x)
|
set (GNUCASH_LATEST_STABLE_SERIES 3.x)
|
||||||
|
|
||||||
set (PACKAGE gnucash)
|
set (PACKAGE gnucash)
|
||||||
set (PACKAGE_NAME GnuCash)
|
set (PACKAGE_NAME GnuCash)
|
||||||
set (PACKAGE_VERSION 3.5)
|
set (PACKAGE_VERSION 3.900)
|
||||||
set (PACKAGE_BUGREPORT "https://bugs.gnucash.org")
|
set (PACKAGE_BUGREPORT "https://bugs.gnucash.org")
|
||||||
set (PACKAGE_TARNAME ${PACKAGE})
|
set (PACKAGE_TARNAME ${PACKAGE})
|
||||||
set (PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
set (PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
<property name="default_height">600</property>
|
<property name="default_height">600</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<signal name="map" handler="gnc_ui_generic_account_picker_map_cb" swapped="no"/>
|
<signal name="map" handler="gnc_ui_generic_account_picker_map_cb" swapped="no"/>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="account_picker_vbox">
|
<object class="GtkBox" id="account_picker_vbox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -165,7 +168,6 @@
|
|||||||
<property name="page_increment">10</property>
|
<property name="page_increment">10</property>
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkDialog" id="format_picker_dialog">
|
<object class="GtkDialog" id="format_picker_dialog">
|
||||||
<property name="visible">False</property>
|
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="title" translatable="yes">Choose a format</property>
|
<property name="title" translatable="yes">Choose a format</property>
|
||||||
<property name="resizable">False</property>
|
<property name="resizable">False</property>
|
||||||
@ -173,6 +175,9 @@
|
|||||||
<property name="default_width">600</property>
|
<property name="default_width">600</property>
|
||||||
<property name="default_height">400</property>
|
<property name="default_height">400</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="dialog-vbox16">
|
<object class="GtkBox" id="dialog-vbox16">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -301,6 +306,9 @@
|
|||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="title" translatable="yes">Preferences</property>
|
<property name="title" translatable="yes">Preferences</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkGrid" id="matcher_prefs">
|
<object class="GtkGrid" id="matcher_prefs">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -554,6 +562,9 @@
|
|||||||
<property name="default_width">600</property>
|
<property name="default_width">600</property>
|
||||||
<property name="default_height">400</property>
|
<property name="default_height">400</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="dialog-vbox14">
|
<object class="GtkBox" id="dialog-vbox14">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -717,7 +728,8 @@
|
|||||||
<property name="text" translatable="yes">This transaction requires your intervention or it will NOT be imported.</property>
|
<property name="text" translatable="yes">This transaction requires your intervention or it will NOT be imported.</property>
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkTextBuffer" id="textbuffer5">
|
<object class="GtkTextBuffer" id="textbuffer5">
|
||||||
<property name="text" translatable="yes">Double click on the transaction to change the matching transaction to reconcile, or the destination account of the auto-balance split (if required).</property>
|
<property name="text" translatable="yes">Double click on the transaction to change the matching transaction to reconcile, or the destination account of the auto-balance split (if required).
|
||||||
|
Multiply select rows using Ctrl-Click, Shift-Click and Rubber banding . Right-Click or Shift-F10 to bring up popup menu and click or select to assign a destination account to the selected rows.</property>
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkDialog" id="matcher_help_dialog">
|
<object class="GtkDialog" id="matcher_help_dialog">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
@ -726,6 +738,9 @@
|
|||||||
<property name="resizable">False</property>
|
<property name="resizable">False</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<signal name="close" handler="on_matcher_help_close_clicked" swapped="no"/>
|
<signal name="close" handler="on_matcher_help_close_clicked" swapped="no"/>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="dialog-vbox18">
|
<object class="GtkBox" id="dialog-vbox18">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -764,6 +779,7 @@
|
|||||||
<object class="GtkGrid" id="table1">
|
<object class="GtkGrid" id="table1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">42</property>
|
||||||
<property name="row_spacing">6</property>
|
<property name="row_spacing">6</property>
|
||||||
<property name="column_spacing">12</property>
|
<property name="column_spacing">12</property>
|
||||||
<child>
|
<child>
|
||||||
@ -990,6 +1006,7 @@
|
|||||||
<object class="GtkTextView" id="textview5">
|
<object class="GtkTextView" id="textview5">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
|
<property name="margin_bottom">2</property>
|
||||||
<property name="pixels_above_lines">5</property>
|
<property name="pixels_above_lines">5</property>
|
||||||
<property name="pixels_below_lines">5</property>
|
<property name="pixels_below_lines">5</property>
|
||||||
<property name="editable">False</property>
|
<property name="editable">False</property>
|
||||||
@ -1107,8 +1124,11 @@
|
|||||||
<property name="reorderable">True</property>
|
<property name="reorderable">True</property>
|
||||||
<property name="rules_hint">True</property>
|
<property name="rules_hint">True</property>
|
||||||
<property name="enable_search">False</property>
|
<property name="enable_search">False</property>
|
||||||
|
<property name="rubber_banding">True</property>
|
||||||
<child internal-child="selection">
|
<child internal-child="selection">
|
||||||
<object class="GtkTreeSelection" id="treeview-selection3"/>
|
<object class="GtkTreeSelection" id="treeview-selection3">
|
||||||
|
<property name="mode">multiple</property>
|
||||||
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
@ -1145,6 +1165,9 @@
|
|||||||
<property name="default_height">400</property>
|
<property name="default_height">400</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<signal name="close" handler="on_matcher_cancel_clicked" swapped="no"/>
|
<signal name="close" handler="on_matcher_cancel_clicked" swapped="no"/>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="transaction_matcher_vbox">
|
<object class="GtkBox" id="transaction_matcher_vbox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -98,9 +98,28 @@ void on_matcher_help_clicked (GtkButton *button, gpointer user_data);
|
|||||||
void on_matcher_help_close_clicked (GtkButton *button, gpointer user_data);
|
void on_matcher_help_close_clicked (GtkButton *button, gpointer user_data);
|
||||||
|
|
||||||
/* Local prototypes */
|
/* Local prototypes */
|
||||||
static void
|
static void gnc_gen_trans_assign_transfer_account(
|
||||||
refresh_model_row(GNCImportMainMatcher *gui, GtkTreeModel *model,
|
GtkTreeView *treeview,
|
||||||
|
gboolean *first,
|
||||||
|
gboolean *is_selection,
|
||||||
|
GtkTreePath *path,
|
||||||
|
Account **new_acc,
|
||||||
|
GNCImportMainMatcher *info);
|
||||||
|
static void gnc_gen_trans_assign_transfer_account_to_selection_cb (
|
||||||
|
GtkMenuItem *menuitem,
|
||||||
|
GNCImportMainMatcher *info);
|
||||||
|
static void gnc_gen_trans_view_popup_menu (GtkTreeView *treeview,
|
||||||
|
GdkEvent *event,
|
||||||
|
GNCImportMainMatcher *info);
|
||||||
|
static gboolean gnc_gen_trans_onButtonPressed_cb (GtkTreeView *treeview,
|
||||||
|
GdkEvent *event,
|
||||||
|
GNCImportMainMatcher *info);
|
||||||
|
static gboolean gnc_gen_trans_onPopupMenu_cb (GtkTreeView *treeview,
|
||||||
|
GdkEvent *event,
|
||||||
|
GNCImportMainMatcher *info);
|
||||||
|
static void refresh_model_row(GNCImportMainMatcher *gui, GtkTreeModel *model,
|
||||||
GtkTreeIter *iter, GNCImportTransInfo *info);
|
GtkTreeIter *iter, GNCImportTransInfo *info);
|
||||||
|
/* end local prototypes */
|
||||||
|
|
||||||
void gnc_gen_trans_list_delete (GNCImportMainMatcher *info)
|
void gnc_gen_trans_list_delete (GNCImportMainMatcher *info)
|
||||||
{
|
{
|
||||||
@ -361,54 +380,238 @@ gnc_gen_trans_update_toggled_cb (GtkCellRendererToggle *cell_renderer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gnc_gen_trans_row_activated_cb (GtkTreeView *view,
|
gnc_gen_trans_assign_transfer_account(GtkTreeView *treeview,
|
||||||
GtkTreePath *path,
|
gboolean *first,
|
||||||
GtkTreeViewColumn *column,
|
gboolean *is_selection,
|
||||||
GNCImportMainMatcher *gui)
|
GtkTreePath *path,
|
||||||
|
Account **new_acc,
|
||||||
|
GNCImportMainMatcher *info)
|
||||||
{
|
{
|
||||||
GtkTreeModel *model;
|
GtkTreeModel *model;
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
GNCImportTransInfo *trans_info;
|
GNCImportTransInfo *trans_info;
|
||||||
|
Account *old_acc;
|
||||||
|
gboolean ok_pressed;
|
||||||
|
|
||||||
model = gtk_tree_view_get_model(gui->view);
|
ENTER("");
|
||||||
if (!gtk_tree_model_get_iter(model, &iter, path))
|
DEBUG("first = %s",*first?"true":"false");
|
||||||
return;
|
DEBUG("is_selection = %s",*is_selection?"true":"false");
|
||||||
gtk_tree_model_get(model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
|
DEBUG("path = %s", gtk_tree_path_to_string(path));
|
||||||
|
DEBUG("account passed in = %s", gnc_get_account_name_for_register(*new_acc));
|
||||||
switch (gnc_import_TransInfo_get_action (trans_info))
|
model = gtk_tree_view_get_model(treeview);
|
||||||
|
if (gtk_tree_model_get_iter(model, &iter, path))
|
||||||
{
|
{
|
||||||
case GNCImport_ADD:
|
gtk_tree_model_get(model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
|
||||||
if (gnc_import_TransInfo_is_balanced(trans_info) == FALSE)
|
|
||||||
|
switch (gnc_import_TransInfo_get_action (trans_info))
|
||||||
{
|
{
|
||||||
run_account_picker_dialog (gui, model, &iter, trans_info);
|
case GNCImport_ADD:
|
||||||
|
if (gnc_import_TransInfo_is_balanced(trans_info) == FALSE)
|
||||||
|
{
|
||||||
|
ok_pressed = TRUE;
|
||||||
|
old_acc = gnc_import_TransInfo_get_destacc (trans_info);
|
||||||
|
if (*first)
|
||||||
|
{
|
||||||
|
ok_pressed = FALSE;
|
||||||
|
*new_acc = gnc_import_select_account(info->main_widget,
|
||||||
|
NULL,
|
||||||
|
TRUE,
|
||||||
|
_("Destination account for the auto-balance split."),
|
||||||
|
xaccTransGetCurrency(
|
||||||
|
gnc_import_TransInfo_get_trans(trans_info)),
|
||||||
|
ACCT_TYPE_NONE,
|
||||||
|
old_acc,
|
||||||
|
&ok_pressed);
|
||||||
|
*first = FALSE;
|
||||||
|
DEBUG("account selected = %s",
|
||||||
|
gnc_account_get_full_name(*new_acc));
|
||||||
|
}
|
||||||
|
if (ok_pressed)
|
||||||
|
gnc_import_TransInfo_set_destacc (trans_info,
|
||||||
|
*new_acc, TRUE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GNCImport_CLEAR:
|
||||||
|
case GNCImport_UPDATE:
|
||||||
|
if (first && !is_selection) run_match_dialog (info, trans_info);
|
||||||
|
break;
|
||||||
|
case GNCImport_SKIP:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PERR("InvalidGNCImportValue");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
refresh_model_row(info, model, &iter, trans_info);
|
||||||
case GNCImport_CLEAR:
|
|
||||||
case GNCImport_UPDATE:
|
|
||||||
run_match_dialog (gui, trans_info);
|
|
||||||
break;
|
|
||||||
case GNCImport_SKIP:
|
|
||||||
/*The information displayed is only informative, until you select an action*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PERR("I don't know what to do! (Yet...)");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
refresh_model_row(gui, model, &iter, trans_info);
|
LEAVE("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gnc_gen_trans_assign_transfer_account_to_selection_cb (GtkMenuItem *menuitem,
|
||||||
|
GNCImportMainMatcher *info)
|
||||||
|
{
|
||||||
|
GtkTreeView *treeview;
|
||||||
|
GtkTreeSelection *selection;
|
||||||
|
GtkTreeModel *model;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
GNCImportTransInfo *trans_info;
|
||||||
|
Account *assigned_account;
|
||||||
|
GList *selected_rows, *l;
|
||||||
|
gboolean first, is_selection;
|
||||||
|
|
||||||
|
ENTER("");
|
||||||
|
treeview = GTK_TREE_VIEW(info->view);
|
||||||
|
model = gtk_tree_view_get_model(treeview);
|
||||||
|
selection = gtk_tree_view_get_selection(treeview);
|
||||||
|
selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
|
||||||
|
assigned_account = NULL;
|
||||||
|
first = TRUE;
|
||||||
|
is_selection = TRUE;
|
||||||
|
DEBUG("Rows in selection = %i",
|
||||||
|
gtk_tree_selection_count_selected_rows(selection));
|
||||||
|
DEBUG("Entering loop over selection");
|
||||||
|
|
||||||
|
for (l = selected_rows; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
DEBUG("passing first = %s",
|
||||||
|
first?"true":"false");
|
||||||
|
DEBUG("passing is_selection = %s",
|
||||||
|
is_selection?"true":"false");
|
||||||
|
DEBUG("passing path = %s",
|
||||||
|
gtk_tree_path_to_string(l->data));
|
||||||
|
DEBUG("passing account value = %s",
|
||||||
|
gnc_account_get_full_name(assigned_account));
|
||||||
|
gnc_gen_trans_assign_transfer_account(treeview,
|
||||||
|
&first, &is_selection, l->data, &assigned_account, info);
|
||||||
|
DEBUG("returned value of account = %s",
|
||||||
|
gnc_account_get_full_name(assigned_account));
|
||||||
|
DEBUG("returned value of first = %s",first?"true":"false");
|
||||||
|
if (assigned_account == NULL) break;
|
||||||
|
gtk_tree_selection_unselect_path(selection, l->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
|
||||||
|
g_list_free_full(l, (GDestroyNotify) gtk_tree_path_free);
|
||||||
|
LEAVE("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gnc_gen_trans_row_activated_cb (GtkTreeView *treeview,
|
||||||
|
GtkTreePath *path,
|
||||||
|
GtkTreeViewColumn *column,
|
||||||
|
GNCImportMainMatcher *info)
|
||||||
|
{
|
||||||
|
Account *assigned_account;
|
||||||
|
gboolean first, is_selection;
|
||||||
|
|
||||||
|
ENTER("");
|
||||||
|
assigned_account = NULL;
|
||||||
|
first = TRUE;
|
||||||
|
is_selection = FALSE;
|
||||||
|
gnc_gen_trans_assign_transfer_account(treeview,
|
||||||
|
&first, &is_selection, path,
|
||||||
|
&assigned_account, info);
|
||||||
|
DEBUG("account returned = %s", gnc_account_get_full_name(assigned_account));
|
||||||
|
LEAVE("");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gnc_gen_trans_row_changed_cb (GtkTreeSelection *selection,
|
gnc_gen_trans_row_changed_cb (GtkTreeSelection *selection,
|
||||||
GNCImportMainMatcher *gui)
|
GNCImportMainMatcher *info)
|
||||||
{
|
{
|
||||||
GtkTreeModel *model;
|
GtkTreeModel *model;
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
|
GtkSelectionMode mode;
|
||||||
|
|
||||||
if (!gtk_tree_selection_get_selected(selection, &model, &iter))
|
ENTER("");
|
||||||
return;
|
mode = gtk_tree_selection_get_mode(selection);
|
||||||
gtk_tree_selection_unselect_iter(selection, &iter);
|
switch (mode)
|
||||||
|
{
|
||||||
|
case GTK_SELECTION_MULTIPLE:
|
||||||
|
DEBUG("mode = GTK_SELECTION_MULTIPLE, no action");
|
||||||
|
break;
|
||||||
|
case GTK_SELECTION_NONE:
|
||||||
|
DEBUG("mode = GTK_SELECTION_NONE, no action");
|
||||||
|
break;
|
||||||
|
case GTK_SELECTION_BROWSE:
|
||||||
|
DEBUG("mode = GTK_SELECTION_BROWSE->default");
|
||||||
|
case GTK_SELECTION_SINGLE:
|
||||||
|
DEBUG("mode = GTK_SELECTION_SINGLE->default");
|
||||||
|
default:
|
||||||
|
DEBUG("mode = default unselect selected row");
|
||||||
|
if (gtk_tree_selection_get_selected(selection, &model, &iter))
|
||||||
|
{
|
||||||
|
gtk_tree_selection_unselect_iter(selection, &iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LEAVE("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gnc_gen_trans_view_popup_menu (GtkTreeView *treeview,
|
||||||
|
GdkEvent *event,
|
||||||
|
GNCImportMainMatcher *info)
|
||||||
|
{
|
||||||
|
GtkWidget *menu, *menuitem;
|
||||||
|
GdkEventButton *event_button;
|
||||||
|
|
||||||
|
ENTER ("");
|
||||||
|
menu = gtk_menu_new();
|
||||||
|
menuitem = gtk_menu_item_new_with_label(_("Assign a transfer account."));
|
||||||
|
g_signal_connect(menuitem, "activate",
|
||||||
|
G_CALLBACK(
|
||||||
|
gnc_gen_trans_assign_transfer_account_to_selection_cb),
|
||||||
|
info);
|
||||||
|
DEBUG("Callback to assign destination account to selection connected");
|
||||||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
gtk_widget_show_all(menu);
|
||||||
|
event_button = (GdkEventButton *) event;
|
||||||
|
/* Note: event can be NULL here when called from view_onPopupMenu;
|
||||||
|
* gdk_event_get_time() accepts a NULL argument */
|
||||||
|
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
|
||||||
|
(event_button != NULL) ? event_button->button : 0,
|
||||||
|
gdk_event_get_time((GdkEvent*)event));
|
||||||
|
LEAVE ("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gnc_gen_trans_onButtonPressed_cb (GtkTreeView *treeview,
|
||||||
|
GdkEvent *event,
|
||||||
|
GNCImportMainMatcher *info)
|
||||||
|
{
|
||||||
|
GdkEventButton *event_button;
|
||||||
|
ENTER("");
|
||||||
|
g_return_val_if_fail (treeview != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (event != NULL, FALSE);
|
||||||
|
/* handle single click with the right mouse button? */
|
||||||
|
if (event->type == GDK_BUTTON_PRESS)
|
||||||
|
{
|
||||||
|
event_button = (GdkEventButton *) event;
|
||||||
|
if (event_button->button == GDK_BUTTON_SECONDARY)
|
||||||
|
{
|
||||||
|
DEBUG("Right mouseClick detected- popup the menu.");
|
||||||
|
gnc_gen_trans_view_popup_menu(treeview, event, info);
|
||||||
|
LEAVE("return TRUE");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LEAVE("return FALSE");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gnc_gen_trans_onPopupMenu_cb (GtkTreeView *treeview,
|
||||||
|
GdkEvent *event,
|
||||||
|
GNCImportMainMatcher *info)
|
||||||
|
{
|
||||||
|
ENTER("");
|
||||||
|
/* respond to Shift-F10 popup menu hotkey */
|
||||||
|
gnc_gen_trans_view_popup_menu(treeview, NULL, info);
|
||||||
|
LEAVE ("");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GtkTreeViewColumn *
|
static GtkTreeViewColumn *
|
||||||
add_text_column(GtkTreeView *view, const gchar *title, int col_num)
|
add_text_column(GtkTreeView *view, const gchar *title, int col_num)
|
||||||
{
|
{
|
||||||
@ -536,6 +739,11 @@ gnc_gen_trans_init_view (GNCImportMainMatcher *info,
|
|||||||
G_CALLBACK(gnc_gen_trans_row_activated_cb), info);
|
G_CALLBACK(gnc_gen_trans_row_activated_cb), info);
|
||||||
g_signal_connect(selection, "changed",
|
g_signal_connect(selection, "changed",
|
||||||
G_CALLBACK(gnc_gen_trans_row_changed_cb), info);
|
G_CALLBACK(gnc_gen_trans_row_changed_cb), info);
|
||||||
|
|
||||||
|
g_signal_connect(view, "button-press-event",
|
||||||
|
G_CALLBACK(gnc_gen_trans_onButtonPressed_cb), info);
|
||||||
|
g_signal_connect(view, "popup-menu",
|
||||||
|
G_CALLBACK(gnc_gen_trans_onPopupMenu_cb), info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -182,3 +182,171 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
;; Further options to match what some (several? many?) lenders do (at
|
||||||
|
;; least in Canada):
|
||||||
|
;; The posted interest rate is an annual rate that has a specified
|
||||||
|
;; compounding frequency per year (2 for mortgages in Canada).
|
||||||
|
;; A payment frequency and amortization length are selected (e.g.
|
||||||
|
;; monthly payments for 25 years).
|
||||||
|
;; The posted nominal rate is converted from the specified compounding
|
||||||
|
;; frequency to the equivalent rate at the payment frequency.
|
||||||
|
;; The required payment is calculated.
|
||||||
|
;; The payment is rounded up to the next dollar (or $10 dollars,
|
||||||
|
;; or whatever...)
|
||||||
|
;; Each payment period, interest is calculated on the outstanding
|
||||||
|
;; balance.
|
||||||
|
;; The interest is rounded to the nearest cent and added to the
|
||||||
|
;; balance.
|
||||||
|
;; The payment is subtracted from the balance.
|
||||||
|
;; The final payment will be smaller because all the other payments
|
||||||
|
;; were rounded up.
|
||||||
|
;;
|
||||||
|
;; For the purpose of creating scheduled transactions that properly
|
||||||
|
;; debit a source account while crediting the loan account and the
|
||||||
|
;; interest expense account, the first part (the calculation of the
|
||||||
|
;; required payment) doesn't really matter. You have agreed
|
||||||
|
;; with the lender what the payment terms (interest rate, payment
|
||||||
|
;; frequency, payment amount) will be; you keep paying until the
|
||||||
|
;; balance is zero.
|
||||||
|
;;
|
||||||
|
;; To create the scheduled transactions, we need to build an
|
||||||
|
;; amortization table.
|
||||||
|
;; If it weren't for the rounding of the interest to the nearest cent
|
||||||
|
;; each period, we could calculate the ith row of the amortization
|
||||||
|
;; table directly from the general annuity equation (as is done by
|
||||||
|
;; gnc:ipmt and gnc:ppmt). But to deal with the intermediate
|
||||||
|
;; rounding, the amortization table has to be constructed iteratively
|
||||||
|
;; (as is done by the AMORT worksheet on the TI BA II Plus
|
||||||
|
;; financial calculator).
|
||||||
|
;;
|
||||||
|
;; =================================
|
||||||
|
;; EXAMPLE:
|
||||||
|
;; Say you borrow $100,000 at 5%/yr, compounded semi-annually.
|
||||||
|
;; You amortize the loan over 2 years with 24 monthly payments.
|
||||||
|
;; This calls for payments of $4,384.8418 at the end of each month.
|
||||||
|
;; The lender rounds this up to $4,385.
|
||||||
|
;;
|
||||||
|
;; If you calculate the balance at each period directly using the annuity
|
||||||
|
;; formula (like calc-principal does), and then use the those values to calculate
|
||||||
|
;; the principal and interest paid, the first 10 rows of the amortization table
|
||||||
|
;; look like this (the values are rounded to the nearest cent for _display_, but
|
||||||
|
;; not for calculating the next period):
|
||||||
|
;;
|
||||||
|
;; PERIOD | Open | Interest | Principal | End
|
||||||
|
;; 1 |$100,000.00 | $412.39 | $3,972.61 | $96,027.39
|
||||||
|
;; 2 | $96,027.39 | $396.01 | $3,988.99 | $92,038.40
|
||||||
|
;; 3 | $92,038.40 | $379.56 | $4,005.44 | $88,032.96
|
||||||
|
;; 4 | $88,032.96 | $363.04 | $4,021.96 | $84,011.00
|
||||||
|
;; 5 | $84,011.00 | $346.45 | $4,038.55 | $79,972.45
|
||||||
|
;; 6 | $79,972.45 | $329.80 | $4,055.20 | $75,917.25
|
||||||
|
;; 7 | $75,917.25 | $313.08 | $4,071.92 | $71,845.33
|
||||||
|
;; 8 | $71,845.33 | $296.28 | $4,088.72 | $67,756.61
|
||||||
|
;; 9 | $67,756.61 | $279.43 | $4,105.57 | $63,651.04
|
||||||
|
;; 10 | $63,651.04 | $262.49 | $4,122.51 | $59,528.53
|
||||||
|
;;
|
||||||
|
;; If you calculate each period sequentially (rounding the interest and balance
|
||||||
|
;; at each step), you get:
|
||||||
|
;;
|
||||||
|
;; PERIOD | Open | Interest | Principal | End
|
||||||
|
;; 1 |$100,000.00 | $412.39 | $3,972.61 | $96,027.39
|
||||||
|
;; 2 | $96,027.39 | $396.01 | $3,988.99 | $92,038.40
|
||||||
|
;; 3 | $92,038.40 | $379.56 | $4,005.44 | $88,032.96
|
||||||
|
;; 4 | $88,032.96 | $363.04 | $4,021.96 | $84,011.00
|
||||||
|
;; 5 | $84,011.00 | $346.45 | $4,038.55 | $79,972.45
|
||||||
|
;; 6 | $79,972.45 | $329.80 | $4,055.20 | $75,917.25
|
||||||
|
;; 7 | $75,917.25 | $313.08 | $4,071.92 | $71,845.33
|
||||||
|
;; 8 | $71,845.33 | $296.28 | $4,088.72 | $67,756.61
|
||||||
|
;; 9 | $67,756.61 | $279.42 | $4,105.58 | $63,651.03 <- Different
|
||||||
|
;; 10 | $63,651.03 | $262.49 | $4,122.51 | $59,528.52 <- still $0.01 off
|
||||||
|
;;
|
||||||
|
;; =================================
|
||||||
|
;;
|
||||||
|
;; For the following functions the argument names are:
|
||||||
|
;; py: payment frequency (number of payments per year)
|
||||||
|
;; cy: compounding frequency of the nominal rate (per year)
|
||||||
|
;; iy: nominal annual interest rate
|
||||||
|
;; pv: the present value (opening balance)
|
||||||
|
;; pmt: the size of the periodic payment
|
||||||
|
;; n: the payment period we are asking about (the first payment is n=1)
|
||||||
|
;; places: number of decimal places to round the interest amount to
|
||||||
|
;; at each payment (999 does no rounding)
|
||||||
|
;;
|
||||||
|
;; Note: only ordinary annuities are supported (payments at the end of
|
||||||
|
;; each period, not at the beginning of each period)
|
||||||
|
;;
|
||||||
|
;; Unlike the AMORT worksheet on the BA II Plus, these methods will
|
||||||
|
;; handle the smaller payment (bringing the balance to zero, then
|
||||||
|
;; zeroing future payments)
|
||||||
|
;;
|
||||||
|
;; The present value (pv) must be non-negative. If not, the balance will be
|
||||||
|
;; treated as 0.
|
||||||
|
;; The payment (pmt) can be positive (paying interest, and hopefully
|
||||||
|
;; reducing the balance each payment), or negative (increasing the balance
|
||||||
|
; each payment).
|
||||||
|
;; The payment number (n) must be positive for amort_pmt, amort_ppmt, and
|
||||||
|
;; amort_ipmt. I.e., the first payment is payment 1.
|
||||||
|
;; The payment number (n) must be non-negative for amort_balance. (In this
|
||||||
|
;; case, payment zero is at the _beginning_ of the first period, so
|
||||||
|
;; amort_balance will just be the initial balance.)
|
||||||
|
;; If the above conditions on n are violated, the functions return -1 (#f is
|
||||||
|
;; not used, because it causes gnucash to crash).
|
||||||
|
;;
|
||||||
|
;; A negative interest rate works (if you can find a lender who charges
|
||||||
|
;; negative rates), but negative compounding frequency, or negative payment
|
||||||
|
;; frequency is a bad idea.
|
||||||
|
|
||||||
|
;; Calculate the balance remaining after the nth payment
|
||||||
|
;; (n must be greater than or equal to zero)
|
||||||
|
(define (gnc:amort_pmt py cy iy pv pmt n places)
|
||||||
|
(if (< n 1) -1 ;; Returning #f here causes gnucash to crash on startup
|
||||||
|
(let* ((prevBal (gnc:amort_balance py cy iy pv pmt (- n 1) places))
|
||||||
|
(balBeforePayment
|
||||||
|
(amort_balanceAfterInterest prevBal py cy iy places))
|
||||||
|
(balAfterPayment (amort_balanceAfterPayment balBeforePayment pmt)))
|
||||||
|
(- balBeforePayment balAfterPayment))))
|
||||||
|
|
||||||
|
;; Calculate the amount of the nth payment that is principal
|
||||||
|
;; (n must be greater than zero)
|
||||||
|
(define (gnc:amort_ppmt py cy iy pv pmt n places)
|
||||||
|
(if (< n 1) -1
|
||||||
|
(let* ((prevBal (gnc:amort_balance py cy iy pv pmt (- n 1) places))
|
||||||
|
(bal-after-int (amort_balanceAfterInterest prevBal py cy iy places))
|
||||||
|
(newBal (amort_balanceAfterPayment bal-after-int pmt)))
|
||||||
|
(- prevBal newBal))))
|
||||||
|
|
||||||
|
;; Calculate the amount of the nth payment that is interest
|
||||||
|
;; (n must be greater than zero)
|
||||||
|
(define (gnc:amort_ipmt py cy iy pv pmt n places)
|
||||||
|
(if (< n 1) -1
|
||||||
|
(let* ((prevBal(gnc:amort_balance py cy iy pv pmt (- n 1) places)))
|
||||||
|
(amort_interest prevBal py cy iy places))))
|
||||||
|
|
||||||
|
;; "Private" helper functions:
|
||||||
|
|
||||||
|
;; Calculate the amount of interest on the current balance,
|
||||||
|
;; rounded to the specified number of decimal places
|
||||||
|
(define (amort_interest balance py cy iy places)
|
||||||
|
(roundToPlaces (* balance (gnc:periodic_rate iy py cy)) places)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Calculate the new balance after applying the interest, but before
|
||||||
|
;; applying the payment
|
||||||
|
(define (amort_balanceAfterInterest prevBalance py cy iy places)
|
||||||
|
(+ prevBalance (amort_interest prevBalance py cy iy places))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Apply the payment to the balance (after the interest has been
|
||||||
|
;; added), without letting the balance go below zero.
|
||||||
|
(define (amort_balanceAfterPayment balanceBeforePmt pmt)
|
||||||
|
(max 0 (- balanceBeforePmt pmt))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Round the value to the specified number of decimal places.
|
||||||
|
;; 999 places means no rounding (#f is not used, because only numbers can be
|
||||||
|
;; entered in the scheduled transaction editor)
|
||||||
|
(define (roundToPlaces value places)
|
||||||
|
(if (= places 999) value
|
||||||
|
(/ (round (* value (expt 10 places))) (expt 10 places))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user