mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Rework payment dialog to better guide the user
This commit is contained in:
parent
8cc9f1751c
commit
f0f3a8e812
@ -60,6 +60,8 @@ struct _payment_window
|
|||||||
{
|
{
|
||||||
GtkWidget * dialog;
|
GtkWidget * dialog;
|
||||||
|
|
||||||
|
GtkWidget * payment_warning;
|
||||||
|
GtkWidget * ok_button;
|
||||||
GtkWidget * num_entry;
|
GtkWidget * num_entry;
|
||||||
GtkWidget * memo_entry;
|
GtkWidget * memo_entry;
|
||||||
GtkWidget * post_combo;
|
GtkWidget * post_combo;
|
||||||
@ -75,6 +77,8 @@ struct _payment_window
|
|||||||
GncOwner owner;
|
GncOwner owner;
|
||||||
GncInvoice * invoice;
|
GncInvoice * invoice;
|
||||||
Account * post_acct;
|
Account * post_acct;
|
||||||
|
Account * xfer_acct;
|
||||||
|
gnc_numeric amount_tot;
|
||||||
GList * acct_types;
|
GList * acct_types;
|
||||||
GList * acct_commodities;
|
GList * acct_commodities;
|
||||||
|
|
||||||
@ -142,6 +146,7 @@ static gboolean gnc_payment_dialog_has_pre_existing_txn(const PaymentWindow* pw)
|
|||||||
}
|
}
|
||||||
int gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data);
|
int gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data);
|
||||||
void gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer data);
|
void gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer data);
|
||||||
|
void gnc_payment_dialog_xfer_acct_changed_cb (GtkWidget *widget, gpointer data);
|
||||||
void gnc_payment_ok_cb (GtkWidget *widget, gpointer data);
|
void gnc_payment_ok_cb (GtkWidget *widget, gpointer data);
|
||||||
void gnc_payment_cancel_cb (GtkWidget *widget, gpointer data);
|
void gnc_payment_cancel_cb (GtkWidget *widget, gpointer data);
|
||||||
void gnc_payment_window_destroy_cb (GtkWidget *widget, gpointer data);
|
void gnc_payment_window_destroy_cb (GtkWidget *widget, gpointer data);
|
||||||
@ -159,6 +164,80 @@ gnc_payment_window_refresh_handler (GHashTable *changes, gpointer data)
|
|||||||
pw->post_acct = gnc_account_select_combo_fill (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
|
pw->post_acct = gnc_account_select_combo_fill (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gnc_payment_window_check_payment (PaymentWindow *pw)
|
||||||
|
{
|
||||||
|
const char *conflict_msg = NULL;
|
||||||
|
Account *post, *acc;
|
||||||
|
gnc_numeric amount_deb, amount_cred;
|
||||||
|
gboolean enable_xfer_acct = TRUE;
|
||||||
|
GtkTreeSelection *selection;
|
||||||
|
|
||||||
|
if (!pw)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Verify the "post" account */
|
||||||
|
if (!pw->post_acct)
|
||||||
|
{
|
||||||
|
conflict_msg = _("You must enter a valid account name for posting.");
|
||||||
|
goto update_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify the user has selected an owner */
|
||||||
|
gnc_owner_get_owner (pw->owner_choice, &(pw->owner));
|
||||||
|
if (!gncOwnerIsValid(&pw->owner))
|
||||||
|
{
|
||||||
|
conflict_msg = _("You must select a company for payment processing.");
|
||||||
|
goto update_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify at least one document is selected */
|
||||||
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
|
||||||
|
if (!gtk_tree_selection_count_selected_rows (selection))
|
||||||
|
{
|
||||||
|
conflict_msg = _("You must select at least one document or pre-payment to process.");
|
||||||
|
goto update_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test the total amount */
|
||||||
|
amount_deb = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit));
|
||||||
|
amount_cred = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit));
|
||||||
|
pw->amount_tot = gnc_numeric_sub (amount_cred, amount_deb,
|
||||||
|
gnc_commodity_get_fraction (xaccAccountGetCommodity (pw->post_acct)),
|
||||||
|
GNC_HOW_RND_ROUND_HALF_UP);
|
||||||
|
|
||||||
|
if (gnc_numeric_check (pw->amount_tot) || gnc_numeric_zero_p (pw->amount_tot))
|
||||||
|
enable_xfer_acct = FALSE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Verify the user has selected a transfer account */
|
||||||
|
pw->xfer_acct = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(pw->acct_tree));
|
||||||
|
if (!pw->xfer_acct)
|
||||||
|
{
|
||||||
|
conflict_msg = _("You must select a transfer account from the account tree.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_cleanup:
|
||||||
|
gtk_widget_set_sensitive (pw->acct_tree, enable_xfer_acct);
|
||||||
|
|
||||||
|
/* Check if there are issues preventing a successful payment */
|
||||||
|
gtk_widget_set_tooltip_text (pw->payment_warning, conflict_msg);
|
||||||
|
if (conflict_msg)
|
||||||
|
{
|
||||||
|
gtk_widget_show (pw->payment_warning);
|
||||||
|
gtk_widget_set_sensitive (pw->ok_button, FALSE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_widget_hide (pw->payment_warning);
|
||||||
|
gtk_widget_set_sensitive (pw->ok_button, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gnc_payment_window_close_handler (gpointer data)
|
gnc_payment_window_close_handler (gpointer data)
|
||||||
{
|
{
|
||||||
@ -237,6 +316,7 @@ gnc_payment_dialog_highlight_document (PaymentWindow *pw)
|
|||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pw->docs_list_tree_view));
|
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pw->docs_list_tree_view));
|
||||||
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
|
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
|
||||||
|
gtk_tree_selection_unselect_all (selection);
|
||||||
|
|
||||||
if (gtk_tree_model_get_iter_first (model, &iter))
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
||||||
{
|
{
|
||||||
@ -260,8 +340,6 @@ gnc_payment_dialog_highlight_document (PaymentWindow *pw)
|
|||||||
gtk_tree_selection_select_iter (selection, &iter);
|
gtk_tree_selection_select_iter (selection, &iter);
|
||||||
gnc_payment_dialog_document_selection_changed (pw);
|
gnc_payment_dialog_document_selection_changed (pw);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
gtk_tree_selection_unselect_iter (selection, &iter);
|
|
||||||
}
|
}
|
||||||
while (gtk_tree_model_iter_next (model, &iter));
|
while (gtk_tree_model_iter_next (model, &iter));
|
||||||
}
|
}
|
||||||
@ -478,6 +556,9 @@ gnc_payment_dialog_owner_changed_cb (GtkWidget *widget, gpointer data)
|
|||||||
gnc_payment_dialog_owner_changed(pw);
|
gnc_payment_dialog_owner_changed(pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reflect if the payment could complete now */
|
||||||
|
gnc_payment_window_check_payment (pw);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,6 +570,20 @@ gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer da
|
|||||||
if (!pw) return;
|
if (!pw) return;
|
||||||
|
|
||||||
gnc_payment_dialog_document_selection_changed (pw);
|
gnc_payment_dialog_document_selection_changed (pw);
|
||||||
|
|
||||||
|
/* Reflect if the payment could complete now */
|
||||||
|
gnc_payment_window_check_payment (pw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_payment_dialog_xfer_acct_changed_cb (GtkWidget *widget, gpointer data)
|
||||||
|
{
|
||||||
|
PaymentWindow *pw = data;
|
||||||
|
|
||||||
|
if (!pw) return;
|
||||||
|
|
||||||
|
/* Reflect if the payment could complete now */
|
||||||
|
gnc_payment_window_check_payment (pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -510,6 +605,9 @@ gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data)
|
|||||||
else
|
else
|
||||||
gnc_payment_dialog_highlight_document (pw);
|
gnc_payment_dialog_highlight_document (pw);
|
||||||
|
|
||||||
|
/* Reflect if the payment could complete now */
|
||||||
|
gnc_payment_window_check_payment (pw);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,56 +639,15 @@ gnc_payment_ok_cb (GtkWidget *widget, gpointer data)
|
|||||||
{
|
{
|
||||||
PaymentWindow *pw = data;
|
PaymentWindow *pw = data;
|
||||||
const char *text = NULL;
|
const char *text = NULL;
|
||||||
Account *post, *acc;
|
|
||||||
gnc_numeric amount_deb, amount_cred, amount_tot;
|
|
||||||
|
|
||||||
if (!pw)
|
if (!pw)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Verify the total amount is non-zero */
|
/* The gnc_payment_window_check_payment function
|
||||||
amount_deb = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit));
|
* ensures we have valid owner, post account, transfer account
|
||||||
amount_cred = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit));
|
* and amount so we can proceed with the payment.
|
||||||
amount_tot = gnc_numeric_sub (amount_cred, amount_deb,
|
* Note: make sure it's called before all entry points to this function !
|
||||||
gnc_commodity_get_fraction (xaccAccountGetCommodity (pw->post_acct)),
|
*/
|
||||||
GNC_HOW_RND_ROUND_HALF_UP);
|
|
||||||
|
|
||||||
if (gnc_numeric_check (amount_tot) || gnc_numeric_zero_p (amount_tot))
|
|
||||||
{
|
|
||||||
text = _("You must enter the amount of the payment. "
|
|
||||||
"The payment amount must not be zero.");
|
|
||||||
gnc_error_dialog (pw->dialog, "%s", text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify the user has selected an owner */
|
|
||||||
gnc_owner_get_owner (pw->owner_choice, &(pw->owner));
|
|
||||||
if (!gncOwnerIsValid(&pw->owner))
|
|
||||||
{
|
|
||||||
text = _("You must select a company for payment processing.");
|
|
||||||
gnc_error_dialog (pw->dialog, "%s", text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify the user has selected a transfer account */
|
|
||||||
acc = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(pw->acct_tree));
|
|
||||||
if (!acc)
|
|
||||||
{
|
|
||||||
text = _("You must select a transfer account from the account tree.");
|
|
||||||
gnc_error_dialog (pw->dialog, "%s", text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify the "post" account */
|
|
||||||
|
|
||||||
post = gnc_account_select_combo_get_active (pw->post_combo);
|
|
||||||
if (!post)
|
|
||||||
{
|
|
||||||
text = _("You must enter a valid account name for posting.");
|
|
||||||
gnc_error_dialog (pw->dialog, "%s", text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ok, now execute the payment */
|
|
||||||
gnc_suspend_gui_refresh ();
|
gnc_suspend_gui_refresh ();
|
||||||
{
|
{
|
||||||
const char *memo, *num;
|
const char *memo, *num;
|
||||||
@ -609,19 +666,19 @@ gnc_payment_ok_cb (GtkWidget *widget, gpointer data)
|
|||||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
|
||||||
gtk_tree_selection_selected_foreach (selection, get_selected_lots, &selected_lots);
|
gtk_tree_selection_selected_foreach (selection, get_selected_lots, &selected_lots);
|
||||||
|
|
||||||
/* If the 'acc' account and the post account don't have the same
|
/* If the 'xfer_acct' account and the post account don't have the same
|
||||||
currency, we need to get the user to specify the exchange rate */
|
currency, we need to get the user to specify the exchange rate */
|
||||||
if (!gnc_commodity_equal(xaccAccountGetCommodity(acc), xaccAccountGetCommodity(post)))
|
if (!gnc_commodity_equal(xaccAccountGetCommodity(pw->xfer_acct), xaccAccountGetCommodity(pw->post_acct)))
|
||||||
{
|
{
|
||||||
XferDialog* xfer;
|
XferDialog* xfer;
|
||||||
|
|
||||||
text = _("The transfer and post accounts are associated with different currencies. Please specify the conversion rate.");
|
text = _("The transfer and post accounts are associated with different currencies. Please specify the conversion rate.");
|
||||||
|
|
||||||
xfer = gnc_xfer_dialog(pw->dialog, acc);
|
xfer = gnc_xfer_dialog(pw->dialog, pw->xfer_acct);
|
||||||
gnc_info_dialog(pw->dialog, "%s", text);
|
gnc_info_dialog(pw->dialog, "%s", text);
|
||||||
|
|
||||||
gnc_xfer_dialog_select_to_account(xfer, post);
|
gnc_xfer_dialog_select_to_account(xfer, pw->post_acct);
|
||||||
gnc_xfer_dialog_set_amount(xfer, amount_tot);
|
gnc_xfer_dialog_set_amount(xfer, pw->amount_tot);
|
||||||
|
|
||||||
/* All we want is the exchange rate so prevent the user from thinking
|
/* All we want is the exchange rate so prevent the user from thinking
|
||||||
it makes sense to mess with other stuff */
|
it makes sense to mess with other stuff */
|
||||||
@ -640,12 +697,13 @@ gnc_payment_ok_cb (GtkWidget *widget, gpointer data)
|
|||||||
auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_BILL, GNC_PREF_AUTO_PAY);
|
auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_BILL, GNC_PREF_AUTO_PAY);
|
||||||
|
|
||||||
gncOwnerApplyPayment (&pw->owner, pw->pre_existing_txn, selected_lots,
|
gncOwnerApplyPayment (&pw->owner, pw->pre_existing_txn, selected_lots,
|
||||||
post, acc, amount_tot, exch, date, memo, num, auto_pay);
|
pw->post_acct, pw->xfer_acct, pw->amount_tot,
|
||||||
|
exch, date, memo, num, auto_pay);
|
||||||
}
|
}
|
||||||
gnc_resume_gui_refresh ();
|
gnc_resume_gui_refresh ();
|
||||||
|
|
||||||
/* Save the transfer account, acc */
|
/* Save the transfer account, xfer_acct */
|
||||||
gnc_payment_dialog_remember_account(pw, acc);
|
gnc_payment_dialog_remember_account(pw, pw->xfer_acct);
|
||||||
|
|
||||||
gnc_ui_payment_window_destroy (pw);
|
gnc_ui_payment_window_destroy (pw);
|
||||||
}
|
}
|
||||||
@ -694,8 +752,9 @@ gnc_payment_acct_tree_row_activated_cb (GtkWidget *widget, GtkTreePath *path,
|
|||||||
else
|
else
|
||||||
gtk_tree_view_expand_row(view, path, FALSE);
|
gtk_tree_view_expand_row(view, path, FALSE);
|
||||||
}
|
}
|
||||||
else
|
else if (gnc_payment_window_check_payment (pw))
|
||||||
/* It's an account without any children, so click the Ok button. */
|
/* It's an account without any children
|
||||||
|
* If all conditions for a valid payment are met click the Ok button. */
|
||||||
gnc_payment_ok_cb(widget, pw);
|
gnc_payment_ok_cb(widget, pw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -717,6 +776,9 @@ gnc_payment_leave_amount_cb (GtkWidget *widget, GdkEventFocus *event,
|
|||||||
GNC_HOW_RND_ROUND_HALF_UP);
|
GNC_HOW_RND_ROUND_HALF_UP);
|
||||||
|
|
||||||
gnc_ui_payment_window_set_amount (pw, amount_tot);
|
gnc_ui_payment_window_set_amount (pw, amount_tot);
|
||||||
|
|
||||||
|
/* Reflect if the payment could complete now */
|
||||||
|
gnc_payment_window_check_payment (pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select the list of accounts to show in the tree */
|
/* Select the list of accounts to show in the tree */
|
||||||
@ -829,6 +891,8 @@ new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
|
|||||||
pw->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "Payment Dialog"));
|
pw->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "Payment Dialog"));
|
||||||
|
|
||||||
/* Grab the widgets and build the dialog */
|
/* Grab the widgets and build the dialog */
|
||||||
|
pw->payment_warning = GTK_WIDGET (gtk_builder_get_object (builder, "payment_warning"));
|
||||||
|
pw->ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "okbutton"));
|
||||||
pw->num_entry = GTK_WIDGET (gtk_builder_get_object (builder, "num_entry"));
|
pw->num_entry = GTK_WIDGET (gtk_builder_get_object (builder, "num_entry"));
|
||||||
pw->memo_entry = GTK_WIDGET (gtk_builder_get_object (builder, "memo_entry"));
|
pw->memo_entry = GTK_WIDGET (gtk_builder_get_object (builder, "memo_entry"));
|
||||||
pw->post_combo = GTK_WIDGET (gtk_builder_get_object (builder, "post_combo"));
|
pw->post_combo = GTK_WIDGET (gtk_builder_get_object (builder, "post_combo"));
|
||||||
@ -957,6 +1021,11 @@ new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
|
|||||||
g_signal_connect (G_OBJECT (pw->acct_tree), "row-activated",
|
g_signal_connect (G_OBJECT (pw->acct_tree), "row-activated",
|
||||||
G_CALLBACK (gnc_payment_acct_tree_row_activated_cb), pw);
|
G_CALLBACK (gnc_payment_acct_tree_row_activated_cb), pw);
|
||||||
|
|
||||||
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->acct_tree));
|
||||||
|
g_signal_connect (G_OBJECT (selection), "changed",
|
||||||
|
G_CALLBACK (gnc_payment_dialog_xfer_acct_changed_cb), pw);
|
||||||
|
|
||||||
|
|
||||||
/* Register with the component manager */
|
/* Register with the component manager */
|
||||||
pw->component_id =
|
pw->component_id =
|
||||||
gnc_register_gui_component (cm_class,
|
gnc_register_gui_component (cm_class,
|
||||||
@ -980,6 +1049,9 @@ new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
|
|||||||
gnc_general_search_grab_focus(GNC_GENERAL_SEARCH(pw->owner_choice));
|
gnc_general_search_grab_focus(GNC_GENERAL_SEARCH(pw->owner_choice));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reflect if the payment could complete now */
|
||||||
|
gnc_payment_window_check_payment (pw);
|
||||||
|
|
||||||
/* Warn the user if they have no valid post-to accounts */
|
/* Warn the user if they have no valid post-to accounts */
|
||||||
{
|
{
|
||||||
const gchar *text;
|
const gchar *text;
|
||||||
|
@ -650,6 +650,18 @@ In case of an over-payment or if no invoice was selected, GnuCash will automatic
|
|||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="payment_warning">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-dialog-warning</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
<property name="secondary">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
Loading…
Reference in New Issue
Block a user