Bug #373415: Replace existing transaction fields by imported transaction marked as reconcile

Patch by Manfred Usselmann:

This patch adds an additional update action to the import matcher as described
above. It can be activated with the online banking preferences dialog.

(Patch changed because of one function name adaption after r19936)

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@20021 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Christian Stimming 2011-01-01 20:57:22 +00:00
parent 1a53e1494a
commit 9ad21c7337
7 changed files with 223 additions and 52 deletions

View File

@ -735,6 +735,7 @@ click "OK".</property>
<child>
<widget class="GtkCheckButton" id="gconf/dialogs/import/generic_matcher/enable_skip">
<property name="label" translatable="yes">Enable skip transaction action</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip" translatable="yes">Enable the SKIP action in the transaction matcher. If enabled, a transaction whose best match's score is in the yellow zone (above the Auto-ADD threshold but below the Auto-CLEAR threshold) will be SKIPed by default.</property>
@ -751,11 +752,12 @@ click "OK".</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="gconf/dialogs/import/generic_matcher/enable_edit">
<property name="label" translatable="yes">Enable edit match action</property>
<widget class="GtkCheckButton" id="gconf/dialogs/import/generic_matcher/enable_update">
<property name="label" translatable="yes">Enable update match action</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip" translatable="yes">Enable the EDIT action in the transaction matcher. NOT YET SUPPORTED</property>
<property name="tooltip" translatable="yes">Enable the UPDATE AND RECONCILE action in the transaction matcher. If enabled, a transaction whose best match's score is above the Auto-CLEAR threshold and has a different date or amount than the matching existing transaction will cause the existing transaction to be updated and cleared by default.</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</widget>
@ -987,7 +989,7 @@ click "OK".</property>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">12</property>
<property name="n_rows">13</property>
<property name="n_columns">2</property>
<property name="column_spacing">12</property>
<property name="row_spacing">6</property>
@ -1128,7 +1130,7 @@ click "OK".</property>
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="xpad">12</property>
<property name="label" translatable="yes">"R"</property>
<property name="label" translatable="yes">"U+R"</property>
</widget>
<packing>
<property name="top_attach">7</property>
@ -1139,6 +1141,20 @@ click "OK".</property>
</child>
<child>
<widget class="GtkLabel" id="label847798">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="xpad">12</property>
<property name="label" translatable="yes">"R"</property>
</widget>
<packing>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label847799">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Select "A" to add the transaction as new.</property>
@ -1153,7 +1169,22 @@ click "OK".</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label847799">
<widget class="GtkLabel" id="label847780">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Select "U+R" to update and reconcile a matching transaction.</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label847781">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Select "R" to reconcile a matching transaction.</property>
@ -1161,8 +1192,8 @@ click "OK".</property>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
@ -1176,8 +1207,8 @@ click "OK".</property>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
@ -1190,8 +1221,8 @@ click "OK".</property>
<property name="label" translatable="yes">(none)</property>
</widget>
<packing>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
@ -1210,14 +1241,14 @@ click "OK".</property>
<property name="wrap_mode">word</property>
<property name="cursor_visible">False</property>
<property name="accepts_tab">False</property>
<property name="text" translatable="yes">"Select Import Action" allows you 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).</property>
</widget>
</child>
</widget>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
<property name="top_attach">10</property>
<property name="bottom_attach">11</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>

View File

@ -103,6 +103,7 @@ struct _matchinfo
Split * split;
/*GNC_match_probability probability;*/
gint probability;
gboolean update_proposed;
};
/* Some simple getters and setters for the above data types. */
@ -596,6 +597,7 @@ static void split_find_match (GNCImportTransInfo * trans_info,
{
GNCImportMatchInfo * match_info;
gint prob = 0;
gboolean update_proposed;
double downloaded_split_amount, match_split_amount;
time_t match_time, download_time;
int datediff_day;
@ -671,6 +673,9 @@ static void split_find_match (GNCImportTransInfo * trans_info,
split anyway and skip the rest of the tests.) */
}
/* Check if date and amount are identical */
update_proposed = (prob < 6);
/* Check number heuristics */
{
const char *new_trans_str = xaccTransGetNum(new_trans);
@ -776,6 +781,7 @@ static void split_find_match (GNCImportTransInfo * trans_info,
match_info = g_new0(GNCImportMatchInfo, 1);
match_info->probability = prob;
match_info->update_proposed = update_proposed;
match_info->split = split;
match_info->trans = xaccSplitGetParent(split);
@ -857,6 +863,9 @@ gboolean
gnc_import_process_trans_item (GncImportMatchMap *matchmap,
GNCImportTransInfo *trans_info)
{
Split * other_split;
gnc_numeric imbalance_value;
/* DEBUG("Begin"); */
g_assert (trans_info);
@ -895,11 +904,11 @@ gnc_import_process_trans_item (GncImportMatchMap *matchmap,
http://gnucash.org/pipermail/gnucash-devel/2003-August/009982.html
Assume that importers won't create transactions involving two or more
currencies so we can use xaccTransGetImbalanceValue. */
gnc_numeric v =
imbalance_value =
gnc_numeric_neg (xaccTransGetImbalanceValue
(gnc_import_TransInfo_get_trans (trans_info)));
xaccSplitSetValue (split, v);
xaccSplitSetAmount (split, v);
xaccSplitSetValue (split, imbalance_value);
xaccSplitSetAmount (split, imbalance_value);
}
/*xaccSplitSetMemo (split, _("Auto-Balance split"));
-- disabled due to popular request */
@ -912,6 +921,92 @@ gnc_import_process_trans_item (GncImportMatchMap *matchmap,
/* Done editing. */
xaccTransCommitEdit(gnc_import_TransInfo_get_trans (trans_info));
return TRUE;
case GNCImport_UPDATE:
{
GNCImportMatchInfo *selected_match =
gnc_import_TransInfo_get_selected_match(trans_info);
/* If there is no selection, ignore this transaction. */
if (!selected_match)
{
PWARN("No matching translaction to be cleared was chosen. Imported transaction will be ignored.");
break;
}
/* Transaction gets not imported but the matching one gets
updated and reconciled. */
if (gnc_import_MatchInfo_get_split(selected_match) == NULL)
{
PERR("The split I am trying to update and reconcile is NULL, shouldn't happen!");
}
else
{
/* Update and reconcile the matching transaction */
/*DEBUG("BeginEdit selected_match")*/
xaccTransBeginEdit(selected_match->trans);
xaccTransSetDatePostedSecs(selected_match->trans,
xaccTransGetDate(xaccSplitGetParent(
gnc_import_TransInfo_get_fsplit(trans_info))));
xaccSplitSetAmount(selected_match->split,
xaccSplitGetAmount(
gnc_import_TransInfo_get_fsplit(trans_info)));
xaccSplitSetValue(selected_match->split,
xaccSplitGetValue(
gnc_import_TransInfo_get_fsplit(trans_info)));
imbalance_value = xaccTransGetImbalanceValue(
gnc_import_TransInfo_get_trans(trans_info));
other_split = xaccSplitGetOtherSplit(selected_match->split);
if (!gnc_numeric_zero_p(imbalance_value) && other_split)
{
if (xaccSplitGetReconcile(other_split) == NREC)
{
imbalance_value = gnc_numeric_neg(imbalance_value);
xaccSplitSetValue(other_split, imbalance_value);
xaccSplitSetAmount(other_split, imbalance_value);
}
/* else GC will automatically insert a split to equity
to balance the transaction */
}
xaccTransSetDescription(selected_match->trans,
xaccTransGetDescription(
gnc_import_TransInfo_get_trans(trans_info)));
if (xaccSplitGetReconcile(selected_match->split) == NREC)
{
xaccSplitSetReconcile(selected_match->split, CREC);
}
/* Set reconcile date to today */
xaccSplitSetDateReconciledSecs(selected_match->split, time(NULL));
/* Copy the online id to the reconciled transaction, so
the match will be remembered */
if (gnc_import_split_has_online_id(trans_info->first_split))
{
gnc_import_set_split_online_id(selected_match->split,
gnc_import_get_split_online_id(trans_info->first_split));
}
/* Done editing. */
/*DEBUG("CommitEdit selected_match")*/
xaccTransCommitEdit(selected_match->trans);
/* Store the mapping to the other account in the MatchMap. */
matchmap_store_destination(matchmap, trans_info, TRUE);
/* Erase the downloaded transaction */
xaccTransDestroy(trans_info->trans);
/*DEBUG("CommitEdit trans")*/
xaccTransCommitEdit(trans_info->trans);
/* Very important: Make sure the freed transaction is not freed again! */
trans_info->trans = NULL;
}
}
return TRUE;
case GNCImport_CLEAR:
{
GNCImportMatchInfo *selected_match =
@ -968,9 +1063,6 @@ gnc_import_process_trans_item (GncImportMatchMap *matchmap,
}
}
return TRUE;
case GNCImport_EDIT:
PERR("EDIT action is UNSUPPORTED!");
break;
default:
DEBUG("Invalid GNCImportAction for this imported transaction.");
}
@ -1117,17 +1209,36 @@ gnc_import_TransInfo_init_matches (GNCImportTransInfo *trans_info,
trans_info->selected_match_info = best_match;
}
else if (best_match == NULL ||
best_match->probability <= gnc_import_Settings_get_add_threshold(settings) )
best_match->probability <= gnc_import_Settings_get_add_threshold(settings))
{
trans_info->action = GNCImport_ADD;
}
else
else if (gnc_import_Settings_get_action_skip_enabled(settings))
{
trans_info->action = GNCImport_SKIP;
}
else if (gnc_import_Settings_get_action_update_enabled(settings))
{
trans_info->action = GNCImport_UPDATE;
}
else
{
trans_info->action = GNCImport_ADD;
}
}
else
{
trans_info->action = GNCImport_ADD;
}
if (best_match &&
trans_info->action == GNCImport_CLEAR &&
gnc_import_Settings_get_action_update_enabled(settings))
{
if (best_match->update_proposed)
{
trans_info->action = GNCImport_UPDATE;
}
}
trans_info->previous_action = trans_info->action;
}

View File

@ -40,7 +40,7 @@ typedef enum _action
GNCImport_SKIP,
GNCImport_ADD,
GNCImport_CLEAR,
GNCImport_EDIT,
GNCImport_UPDATE,
GNCImport_LAST_ACTION,
GNCImport_INVALID_ACTION
} GNCImportAction;

View File

@ -66,7 +66,7 @@ enum downloaded_cols
DOWNLOADED_COL_MEMO,
DOWNLOADED_COL_ACTION_ADD,
DOWNLOADED_COL_ACTION_CLEAR,
DOWNLOADED_COL_ACTION_EDIT,
DOWNLOADED_COL_ACTION_UPDATE,
DOWNLOADED_COL_ACTION_INFO,
DOWNLOADED_COL_ACTION_PIXBUF,
DOWNLOADED_COL_DATA,
@ -330,7 +330,7 @@ gnc_gen_trans_clear_toggled_cb (GtkCellRendererToggle *cell_renderer,
}
static void
gnc_gen_trans_edit_toggled_cb (GtkCellRendererToggle *cell_renderer,
gnc_gen_trans_update_toggled_cb (GtkCellRendererToggle *cell_renderer,
gchar *path,
GNCImportMainMatcher *gui)
{
@ -343,14 +343,14 @@ gnc_gen_trans_edit_toggled_cb (GtkCellRendererToggle *cell_renderer,
return;
gtk_tree_model_get(model, &iter, DOWNLOADED_COL_DATA, &trans_info, -1);
if ( gnc_import_TransInfo_get_action(trans_info) == GNCImport_EDIT
if ( gnc_import_TransInfo_get_action(trans_info) == GNCImport_UPDATE
&& gnc_import_Settings_get_action_skip_enabled (gui->user_settings) == TRUE)
{
gnc_import_TransInfo_set_action(trans_info, GNCImport_SKIP);
}
else
{
gnc_import_TransInfo_set_action(trans_info, GNCImport_EDIT);
gnc_import_TransInfo_set_action(trans_info, GNCImport_UPDATE);
}
refresh_model_row(gui, model, &iter, trans_info);
}
@ -379,6 +379,7 @@ gnc_gen_trans_row_activated_cb (GtkTreeView *view,
}
break;
case GNCImport_CLEAR:
case GNCImport_UPDATE:
run_match_dialog (gui, trans_info);
break;
case GNCImport_SKIP:
@ -452,7 +453,7 @@ add_toggle_column(GtkTreeView *view, const gchar *title, int col_num,
static void
gnc_gen_trans_init_view (GNCImportMainMatcher *info,
gboolean show_account,
gboolean show_edit)
gboolean show_update)
{
GtkTreeView *view;
GtkListStore *store;
@ -478,12 +479,11 @@ gnc_gen_trans_init_view (GNCImportMainMatcher *info,
add_text_column(view, _("Memo"), DOWNLOADED_COL_MEMO);
add_toggle_column(view, _("A"), DOWNLOADED_COL_ACTION_ADD,
G_CALLBACK(gnc_gen_trans_add_toggled_cb), info);
column = add_toggle_column(view, _("U+R"), DOWNLOADED_COL_ACTION_UPDATE,
G_CALLBACK(gnc_gen_trans_update_toggled_cb), info);
gtk_tree_view_column_set_visible(column, show_update);
add_toggle_column(view, _("R"), DOWNLOADED_COL_ACTION_CLEAR,
G_CALLBACK(gnc_gen_trans_clear_toggled_cb), info);
column = add_toggle_column(view, _("Edit"), DOWNLOADED_COL_ACTION_EDIT,
G_CALLBACK(gnc_gen_trans_edit_toggled_cb), info);
gtk_tree_view_column_set_visible(column, show_edit);
/* The last column has multiple renderers */
renderer = gtk_cell_renderer_pixbuf_new();
@ -525,7 +525,7 @@ GNCImportMainMatcher *gnc_gen_trans_list_new (GtkWidget *parent,
GNCImportMainMatcher *info;
GladeXML *xml;
GtkWidget *heading_label;
gboolean show_edit;
gboolean show_update;
info = g_new0 (GNCImportMainMatcher, 1);
@ -541,8 +541,8 @@ GNCImportMainMatcher *gnc_gen_trans_list_new (GtkWidget *parent,
info->view = GTK_TREE_VIEW(glade_xml_get_widget (xml, "downloaded_view"));
g_assert (info->view != NULL);
show_edit = gnc_import_Settings_get_action_edit_enabled (info->user_settings);
gnc_gen_trans_init_view(info, all_from_same_account, show_edit);
show_update = gnc_import_Settings_get_action_update_enabled(info->user_settings);
gnc_gen_trans_init_view(info, all_from_same_account, show_update);
heading_label = glade_xml_get_widget (xml, "heading_label");
g_assert (heading_label != NULL);
@ -725,9 +725,24 @@ refresh_model_row (GNCImportMainMatcher *gui,
ro_text = _("Match missing!");
}
break;
case GNCImport_EDIT:
color = "white";
ro_text = "NOT SUPPORTED YET!";
case GNCImport_UPDATE:
if (gnc_import_TransInfo_get_selected_match(info))
{
color = COLOR_GREEN;
if (gnc_import_TransInfo_get_match_selected_manually(info) == TRUE)
{
ro_text = _("Update and reconcile (manual) match");
}
else
{
ro_text = _("Update and reconcile (auto) match");
}
}
else
{
color = COLOR_RED;
ro_text = _("Match missing!");
}
break;
case GNCImport_SKIP:
color = COLOR_RED;
@ -779,9 +794,20 @@ refresh_model_row (GNCImportMainMatcher *gui,
}
gtk_list_store_set(store, iter,
DOWNLOADED_COL_ACTION_EDIT,
gnc_import_TransInfo_get_action(info) == GNCImport_EDIT,
DOWNLOADED_COL_ACTION_UPDATE,
gnc_import_TransInfo_get_action(info) == GNCImport_UPDATE,
-1);
if (gnc_import_TransInfo_get_action(info) == GNCImport_UPDATE)
{
/*Show the best match's confidence pixmap in the info column*/
gtk_list_store_set(store, iter,
DOWNLOADED_COL_ACTION_PIXBUF,
gen_probability_pixbuf( gnc_import_MatchInfo_get_probability
( gnc_import_TransInfo_get_selected_match (info)),
gui->user_settings,
GTK_WIDGET(gui->view)),
-1);
}
selection = gtk_tree_view_get_selection(gui->view);
gtk_tree_selection_unselect_all(selection);

View File

@ -49,7 +49,7 @@ struct _genimportsettings
{
gboolean action_skip_enabled;
gboolean action_edit_enabled;
gboolean action_update_enabled;
gboolean action_add_enabled;
gboolean action_clear_enabled;
@ -85,8 +85,8 @@ gnc_import_Settings_new (void)
settings->action_skip_enabled =
gnc_gconf_get_bool(GCONF_SECTION, "enable_skip", NULL);
settings->action_edit_enabled =
gnc_gconf_get_bool(GCONF_SECTION, "enable_edit", NULL);
settings->action_update_enabled =
gnc_gconf_get_bool(GCONF_SECTION, "enable_update", NULL);
settings->action_add_enabled = DEFAULT_ACTION_ADD_ENABLED;
settings->action_clear_enabled = DEFAULT_ACTION_CLEAR_ENABLED;
settings->clear_threshold =
@ -131,10 +131,10 @@ gboolean gnc_import_Settings_get_action_add_enabled (GNCImportSettings *settings
return settings->action_add_enabled;
};
gboolean gnc_import_Settings_get_action_edit_enabled (GNCImportSettings *settings)
gboolean gnc_import_Settings_get_action_update_enabled (GNCImportSettings *settings)
{
g_assert (settings);
return settings->action_edit_enabled;
return settings->action_update_enabled;
};
gboolean gnc_import_Settings_get_action_clear_enabled (GNCImportSettings *settings)

View File

@ -66,7 +66,7 @@ gboolean gnc_import_Settings_get_action_add_enabled (GNCImportSettings *settings
/** Return the selected action is enable state.
*/
gboolean gnc_import_Settings_get_action_edit_enabled (GNCImportSettings *settings);
gboolean gnc_import_Settings_get_action_update_enabled (GNCImportSettings *settings);
/** Return the selected action is enable state.
*/

View File

@ -51,16 +51,19 @@
</schema>
<schema>
<key>/schemas/apps/gnucash/dialogs/import/generic_matcher/enable_edit</key>
<applyto>/apps/gnucash/dialogs/import/generic_matcher/enable_edit</applyto>
<key>/schemas/apps/gnucash/dialogs/import/generic_matcher/enable_update</key>
<applyto>/apps/gnucash/dialogs/import/generic_matcher/enable_update</applyto>
<owner>gnucash</owner>
<type>bool</type>
<default>FALSE</default>
<locale name="C">
<short>Enable EDIT transaction action</short>
<short>Enable UPDATE match action</short>
<long>
Enable the EDIT action in the transaction matcher. NOT YET
SUPPORTED.
Enable the UPDATE AND RECONCILE action in the transaction matcher.
If enabled, a transaction whose best match's score is above the
Auto-CLEAR threshold and has a different date or amount than the
matching existing transaction will cause the existing transaction
to be updated and cleared by default.
</long>
</locale>
</schema>