gnucash unstable: Multiple changes pushed

Geert Janssens gjanssens at code.gnucash.org
Sat Nov 18 11:47:27 EST 2017


Updated	 via  https://github.com/Gnucash/gnucash/commit/949f2db4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/cd9c3807 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ce900d1d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d66469fe (commit)
	 via  https://github.com/Gnucash/gnucash/commit/18dcbeef (commit)
	 via  https://github.com/Gnucash/gnucash/commit/aeb80a23 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0dfb921e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/de4414b2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/954ce1ab (commit)
	from  https://github.com/Gnucash/gnucash/commit/61316648 (commit)



commit 949f2db4732283f6f8ac2e1b6cc1a960a3f8f311
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Wed Nov 15 14:30:25 2017 +0100

    Bug 778692 - Assign as payment should work for employee expense vouchers
    
    The way this is implemented is as follows
    - if gnucash can deduce a partner from the transaction that partner will be proposed
      this works for all transactions that are part of a business transaction already
      and will correctly detect pre-existing customer, vendor and employee payments
    - if no partner can be deduced gnucash will assume the transaction to be a vendor
      or customer payment based on the sign
    - in all cases the user can change the partner type in the payment window that's presented
      to any of customer, vendor or employee to correct gnucash' suggestion.

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index efdc193..d45a946 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -54,8 +54,13 @@
 #include "dialog-print-check.h"
 #include "gnc-general-search.h"
 
-#define DIALOG_PAYMENT_CUSTOMER_CM_CLASS "customer-payment-dialog"
-#define DIALOG_PAYMENT_VENDOR_CM_CLASS "vendor-payment-dialog"
+#define DIALOG_PAYMENT_CM_CLASS "payment-dialog"
+
+typedef enum
+{
+    COL_OWNER_TYPE_NAME ,
+    COL_OWNER_TYPE_NUM ,
+} OwnerTypeCols;
 
 typedef struct
 {
@@ -65,10 +70,11 @@ typedef struct
 
 typedef struct
 {
+    GncOwner      owner;
     Transaction * txn;
     Account     * post_acct;
     GList       * lots;
-} PreExistTxnInfo;
+} InitialPaymentInfo;
 
 struct _payment_window
 {
@@ -79,9 +85,13 @@ struct _payment_window
     GtkWidget   * num_entry;
     GtkWidget   * memo_entry;
     GtkWidget   * post_combo;
+    GtkWidget   * owner_box;
+    GtkWidget   * owner_type_combo;
     GtkWidget   * owner_choice;
     GtkWidget   * amount_debit_edit;
     GtkWidget   * amount_credit_edit;
+    GtkWidget   * amount_payment_box;
+    GtkWidget   * amount_refund_box;
     GtkWidget   * date_edit;
     GtkWidget   * acct_tree;
     GtkWidget   * docs_list_tree_view;
@@ -91,13 +101,14 @@ struct _payment_window
     gint          component_id;
     QofBook     * book;
     GncOwner      owner;
+    GncOwnerType  owner_type;
     Account     * post_acct;
     Account     * xfer_acct;
     gnc_numeric   amount_tot;
     GList       * acct_types;
     GList       * acct_commodities;
 
-    PreExistTxnInfo *tx_info;
+    InitialPaymentInfo *tx_info;
     gboolean      print_check_state;
 };
 
@@ -178,6 +189,7 @@ static gboolean gnc_payment_dialog_has_pre_existing_txn(const PaymentWindow* pw)
 {
     return pw->tx_info->txn != NULL;
 }
+int  gnc_payment_dialog_owner_changed_cb (G_GNUC_UNUSED 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_xfer_acct_changed_cb (GtkWidget *widget, gpointer data);
@@ -560,18 +572,16 @@ gnc_payment_window_fill_docs_list (PaymentWindow *pw)
 }
 
 static void
+gnc_payment_dialog_post_to_changed (PaymentWindow *pw)
+{
+    gnc_payment_window_fill_docs_list (pw);
+}
+
+static void
 gnc_payment_dialog_owner_changed (PaymentWindow *pw)
 {
-    Account *last_acct = NULL;
-    GncGUID *guid = NULL;
     GncOwner *owner = &pw->owner;
 
-    /* Now handle the account tree */
-    if (gncOwnerIsValid(owner))
-        qof_instance_get (qofOwnerGetOwner (owner),
-                          "payment-last-account", &guid,
-                          NULL);
-
     /* refresh the post and acc available accounts, but cleanup first */
     if (pw->acct_types)
     {
@@ -588,33 +598,89 @@ gnc_payment_dialog_owner_changed (PaymentWindow *pw)
     pw->acct_types = gncOwnerGetAccountTypesList(owner);
     if (gncOwnerIsValid(owner))
         pw->acct_commodities = gncOwnerGetCommoditiesList (owner);
+
     pw->post_acct = gnc_account_select_combo_fill (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
+    if (gncOwnerEqual(&pw->owner, &pw->tx_info->owner) && pw->tx_info->post_acct)
+    {
+        pw->post_acct = pw->tx_info->post_acct;
+        gnc_ui_payment_window_set_postaccount (pw, pw->post_acct);
+    }
+    gnc_payment_dialog_post_to_changed (pw);
 
     if (pw->post_acct)
         gnc_ui_payment_window_set_commodity (pw, pw->post_acct);
 
-
-    /* Update list of documents and pre-payments */
-    gnc_payment_window_fill_docs_list (pw);
-
-    if (guid)
-    {
-        last_acct = xaccAccountLookup(guid, pw->book);
-    }
-
     /* Set the last-used transfer account, but only if we didn't
      * create this dialog from a pre-existing transaction. */
-    if (last_acct && !gnc_payment_dialog_has_pre_existing_txn(pw))
+    if (!gnc_payment_dialog_has_pre_existing_txn(pw))
     {
-        gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
+        GncGUID *guid = NULL;
+        Account *last_acct = NULL;
+
+        if (gncOwnerIsValid(owner))
+            qof_instance_get (qofOwnerGetOwner (owner),
+                            "payment-last-account", &guid,
+                            NULL);
+        last_acct = xaccAccountLookup(guid, pw->book);
+        if (last_acct)
+            gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
                 last_acct);
     }
 }
 
+
 static void
-gnc_payment_dialog_post_to_changed (PaymentWindow *pw)
+gnc_payment_dialog_owner_type_changed (PaymentWindow *pw)
 {
-    gnc_payment_window_fill_docs_list (pw);
+    GtkWidget *debit_box, *credit_box;
+
+    /* Some terminology:
+     * Invoices are paid, credit notes are refunded.
+     * A customer payment is a credit action, paying a vendor is debit
+     *
+     * So depending on the owner the payment amount should be considered
+     * credit (customer) or debit (vendor/employee) and refunds should be
+     * considered debit (customer) or credit (vendor/employee).
+     * For visual consistency, the dialog box will always show a payment and
+     * a refund field. Internally they are treated as credit or debit depending
+     * on the owner type.
+     */
+    if (pw->owner_type == GNC_OWNER_CUSTOMER)
+    {
+        debit_box = pw->amount_refund_box;
+        credit_box = pw->amount_payment_box;
+    }
+    else
+    {
+        debit_box = pw->amount_payment_box;
+        credit_box = pw->amount_refund_box;
+    }
+
+    g_object_ref (G_OBJECT (pw->amount_debit_edit));
+    g_object_ref (G_OBJECT (pw->amount_credit_edit));
+
+    if (gtk_widget_is_ancestor(pw->amount_debit_edit, credit_box))
+        gtk_container_remove (GTK_CONTAINER (credit_box), pw->amount_debit_edit);
+    if (gtk_widget_is_ancestor(pw->amount_credit_edit, debit_box))
+        gtk_container_remove (GTK_CONTAINER (debit_box), pw->amount_credit_edit);
+
+    if (!gtk_widget_is_ancestor(pw->amount_debit_edit, debit_box))
+        gtk_box_pack_start (GTK_BOX (debit_box), pw->amount_debit_edit, TRUE, TRUE, 0);
+    if (!gtk_widget_is_ancestor(pw->amount_credit_edit, credit_box))
+        gtk_box_pack_start (GTK_BOX (credit_box), pw->amount_credit_edit, TRUE, TRUE, 0);
+
+    g_object_unref (G_OBJECT (pw->amount_debit_edit));
+    g_object_unref (G_OBJECT (pw->amount_credit_edit));
+
+    /* Redo the owner_choice widget */
+    if (pw->owner_choice)
+        gtk_widget_destroy(pw->owner_choice);
+    pw->owner_choice = gnc_owner_select_create (NULL, pw->owner_box, pw->book, &pw->owner);
+    gtk_widget_show (pw->owner_choice);
+    gnc_payment_dialog_owner_changed (pw);
+
+    g_signal_connect (G_OBJECT (pw->owner_choice), "changed",
+                      G_CALLBACK (gnc_payment_dialog_owner_changed_cb), pw);
 }
 
 static void
@@ -641,7 +707,43 @@ gnc_payment_set_owner (PaymentWindow *pw, GncOwner *owner)
     gnc_payment_dialog_owner_changed(pw);
 }
 
-static int
+
+static void
+gnc_payment_set_owner_type (PaymentWindow *pw, GncOwnerType owner_type)
+{
+    gboolean valid;
+    GtkTreeModel *store;
+    GtkTreeIter iter;
+
+    switch (owner_type)
+    {
+        case GNC_OWNER_CUSTOMER:
+        case GNC_OWNER_EMPLOYEE:
+        case GNC_OWNER_VENDOR:
+            pw->owner_type = owner_type;
+            break;
+        default:
+            pw->owner_type = GNC_OWNER_CUSTOMER;
+    }
+
+    store = gtk_combo_box_get_model (GTK_COMBO_BOX(pw->owner_type_combo));
+    valid = gtk_tree_model_get_iter_first (store, &iter);
+    while (valid)
+    {
+        GncOwnerType owner_type;
+        gtk_tree_model_get (store, &iter, COL_OWNER_TYPE_NUM, &owner_type, -1);
+        if (owner_type == pw->owner_type)
+        {
+            gtk_combo_box_set_active_iter (GTK_COMBO_BOX(pw->owner_type_combo), &iter);
+            break;
+        }
+        valid = gtk_tree_model_iter_next (store, &iter);
+    }
+
+    gnc_payment_dialog_owner_type_changed (pw);
+}
+
+int
 gnc_payment_dialog_owner_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
     PaymentWindow *pw = data;
@@ -665,6 +767,55 @@ gnc_payment_dialog_owner_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer d
     return FALSE;
 }
 
+static int
+gnc_payment_dialog_owner_type_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
+{
+    PaymentWindow *pw = data;
+    GtkTreeIter iter;
+    GtkTreeModel *model;
+    GncOwnerType owner_type;
+
+    if (!pw) return FALSE;
+
+    gtk_combo_box_get_active_iter (GTK_COMBO_BOX(pw->owner_type_combo), &iter);
+    model = gtk_combo_box_get_model (GTK_COMBO_BOX(pw->owner_type_combo));
+    gtk_tree_model_get (model, &iter, COL_OWNER_TYPE_NUM, &owner_type, -1);
+
+    if (owner_type != pw->owner_type)
+    {
+        pw->owner_type = owner_type;
+
+        /* If type changed, the currently selected owner can't be valid any more
+         * If the initial owner is of the new owner_type, we propose that one
+         * otherwise we just reset the owner
+         */
+        if (gncOwnerGetType (&pw->tx_info->owner) == pw->owner_type)
+            gncOwnerCopy (&pw->tx_info->owner, &pw->owner);
+        else
+        {
+            switch (pw->owner_type)
+            {
+                case GNC_OWNER_VENDOR:
+                    gncOwnerInitVendor (&pw->owner, NULL);
+                    break;
+                case GNC_OWNER_EMPLOYEE:
+                    gncOwnerInitEmployee (&pw->owner, NULL);
+                    break;
+                default:
+                    gncOwnerInitCustomer (&pw->owner, NULL);
+            }
+
+        }
+
+        gnc_payment_dialog_owner_type_changed (pw);
+    }
+
+    /* Reflect if the payment could complete now */
+    gnc_payment_window_check_payment (pw);
+
+    return FALSE;
+}
+
 void
 gnc_payment_dialog_document_selection_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
@@ -960,22 +1111,22 @@ static void print_date (G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
 }
 
 static PaymentWindow *
-new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
+new_payment_window (GtkWidget *parent, QofBook *book, InitialPaymentInfo *tx_info)
 {
     PaymentWindow *pw;
     GtkBuilder *builder;
-    GtkWidget *box, *label, *credit_box, *debit_box;
+    GtkWidget *box;
     GtkTreeSelection *selection;
     GtkTreeViewColumn *column;
     GtkCellRenderer *renderer;
-    char * cm_class = (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER ?
-                       DIALOG_PAYMENT_CUSTOMER_CM_CLASS :
-                       DIALOG_PAYMENT_VENDOR_CM_CLASS);
+    GtkTreeModel *store;
+    GtkTreeIter iter;
 
     /* Ensure we always have a properly initialized PreExistTxnInfo struct to work with */
     if (!tx_info)
     {
-        tx_info = g_new0 (PreExistTxnInfo, 1);
+        tx_info = g_new0 (InitialPaymentInfo, 1);
+        gncOwnerInitCustomer (&tx_info->owner, NULL);
     }
 
     /*
@@ -984,11 +1135,9 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
      * the window. And update the PreExistTxnInfo (tx_info) for this window.
      */
 
-    pw = gnc_find_first_gui_component (cm_class, find_handler, NULL);
+    pw = gnc_find_first_gui_component (DIALOG_PAYMENT_CM_CLASS, find_handler, NULL);
     if (pw)
     {
-        if (gncOwnerIsValid(owner))
-            gnc_payment_set_owner (pw, owner);
 
         // Reset the current
         if (pw->tx_info->lots)
@@ -996,6 +1145,9 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
         g_free (pw->tx_info);
         pw->tx_info = tx_info;
 
+        gncOwnerCopy (&pw->tx_info->owner, &(pw->owner));
+        gnc_payment_set_owner_type (pw, gncOwnerGetType(&pw->tx_info->owner));
+
         gtk_window_present (GTK_WINDOW(pw->dialog));
         return(pw);
     }
@@ -1005,13 +1157,6 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
     pw = g_new0 (PaymentWindow, 1);
     pw->book = book;
     pw->tx_info = tx_info;
-    gncOwnerCopy (owner, &(pw->owner));
-
-    /* Compute the post-to account types */
-    pw->acct_types = gncOwnerGetAccountTypesList (owner);
-
-    if (gncOwnerIsValid(owner))
-        pw->acct_commodities = gncOwnerGetCommoditiesList (owner);
 
     /* Open and read the Glade File */
     builder = gtk_builder_new();
@@ -1019,6 +1164,7 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
     gnc_builder_add_from_file (builder, "dialog-payment.glade", "docs_list_vert_adj");
     gnc_builder_add_from_file (builder, "dialog-payment.glade", "docs_list_model");
     gnc_builder_add_from_file (builder, "dialog-payment.glade", "post_combo_model");
+    gnc_builder_add_from_file (builder, "dialog-payment.glade", "owner_type_combo_model");
     gnc_builder_add_from_file (builder, "dialog-payment.glade", "payment_dialog");
     pw->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "payment_dialog"));
 
@@ -1035,34 +1181,31 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
     gtk_combo_box_set_entry_text_column( GTK_COMBO_BOX( pw->post_combo ), 0 );
     gnc_cbwe_require_list_item(GTK_COMBO_BOX(pw->post_combo));
 
-    label = GTK_WIDGET (gtk_builder_get_object (builder, "owner_label"));
-    box = GTK_WIDGET (gtk_builder_get_object (builder, "owner_box"));
-    pw->owner_choice = gnc_owner_select_create (label, box, book, owner);
-
-    /* Some terminology:
-     * Invoices are paid, credit notes are refunded.
-     * A customer payment is a credit action, paying a vendor is debit
-     *
-     * So depending on the owner the payment amount should be considered
-     * credit (customer) or debit (vendor/employee) and refunds should be
-     * considered debit (customer) or credit (vendor/employee).
-     * For visual consistency, the dialog box will always show a payment and
-     * a refund field. Internally they are treated as credit or debit depending
-     * on the owner type.
+    pw->owner_type_combo = GTK_WIDGET (gtk_builder_get_object (builder, "owner_type_combo"));
+    /* Add the respective GNC_OWNER_TYPEs to the combo box model
+     * ATTENTION: the order here should match the order of the
+     * store's entries as set in the glade file !
      */
-    if (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER)
-    {
-        debit_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_refund_box"));
-        credit_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_payment_box"));
-    }
-    else
-    {
-        debit_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_payment_box"));
-        credit_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_refund_box"));
-    }
+    store = gtk_combo_box_get_model (GTK_COMBO_BOX(pw->owner_type_combo));
+    gtk_tree_model_get_iter_first (store, &iter);
+    gtk_list_store_set (GTK_LIST_STORE(store), &iter,
+                        COL_OWNER_TYPE_NAME, _("Customer"),
+                        COL_OWNER_TYPE_NUM, GNC_OWNER_CUSTOMER, -1);
+    gtk_tree_model_iter_next (store, &iter);
+    gtk_list_store_set (GTK_LIST_STORE(store), &iter,
+                        COL_OWNER_TYPE_NAME, _("Vendor"),
+                        COL_OWNER_TYPE_NUM, GNC_OWNER_VENDOR, -1);
+    gtk_tree_model_iter_next (store, &iter);
+    gtk_list_store_set (GTK_LIST_STORE(store), &iter,
+                        COL_OWNER_TYPE_NAME, _("Employee"),
+                        COL_OWNER_TYPE_NUM, GNC_OWNER_EMPLOYEE, -1);
+
+    pw->owner_box = GTK_WIDGET (gtk_builder_get_object (builder, "owner_box"));
+
+    pw->amount_refund_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_refund_box"));
+    pw->amount_payment_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_payment_box"));
 
     pw->amount_debit_edit = gnc_amount_edit_new ();
-    gtk_box_pack_start (GTK_BOX (debit_box), pw->amount_debit_edit, TRUE, TRUE, 0);
     gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (pw->amount_debit_edit),
                                            TRUE);
     gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit), gnc_numeric_zero());
@@ -1071,7 +1214,6 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
                      G_CALLBACK(gnc_payment_leave_amount_cb), pw);
 
     pw->amount_credit_edit = gnc_amount_edit_new ();
-    gtk_box_pack_start (GTK_BOX (credit_box), pw->amount_credit_edit, TRUE, TRUE, 0);
     gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (pw->amount_credit_edit),
                                            TRUE);
     gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit), gnc_numeric_zero());
@@ -1104,7 +1246,7 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
     /* Configure document number column */
     column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 1);
     tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
-                                        column, "INV2013-016");
+                                        column, _("Pre-Payment"));
 
     /* Configure document type column */
     column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 2);
@@ -1114,12 +1256,12 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
     /* Configure debit column */
     column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 3);
     tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
-                                        column, "11,999.00");
+                                        column, "9,999,999.00");
 
     /* Configure credit column */
     column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 4);
     tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
-                                        column, "11,999.00");
+                                        column, "9,999,999.00");
 
     gtk_tree_sortable_set_sort_column_id (
         GTK_TREE_SORTABLE (gtk_tree_view_get_model (GTK_TREE_VIEW (pw->docs_list_tree_view))),
@@ -1132,25 +1274,22 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(pw->acct_tree), FALSE);
     gnc_payment_set_account_types (GNC_TREE_VIEW_ACCOUNT (pw->acct_tree));
 
-    /* Set the dialog for the 'new' owner.
+    /* Set the dialog for the 'new' owner and owner type.
      * Note that this also sets the post account tree. */
-    gnc_payment_dialog_owner_changed(pw);
-
-    if (pw->tx_info->post_acct)
-        gnc_ui_payment_window_set_postaccount (pw, tx_info->post_acct);
-    gnc_payment_dialog_post_to_changed_cb (pw->post_combo, pw);
+    gncOwnerCopy (&pw->tx_info->owner, &(pw->owner));
+    gnc_payment_set_owner_type (pw, gncOwnerGetType (&pw->tx_info->owner));
 
     /* Setup signals */
     gtk_builder_connect_signals_full( builder,
                                       gnc_builder_connect_full_func,
                                       pw);
 
-    g_signal_connect (G_OBJECT (pw->owner_choice), "changed",
-                      G_CALLBACK (gnc_payment_dialog_owner_changed_cb), pw);
-
     g_signal_connect (G_OBJECT (pw->acct_tree), "row-activated",
                       G_CALLBACK (gnc_payment_acct_tree_row_activated_cb), pw);
 
+    g_signal_connect (G_OBJECT (pw->owner_type_combo), "changed",
+                      G_CALLBACK (gnc_payment_dialog_owner_type_changed_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);
@@ -1158,7 +1297,7 @@ new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
 
     /* Register with the component manager */
     pw->component_id =
-        gnc_register_gui_component (cm_class,
+        gnc_register_gui_component (DIALOG_PAYMENT_CM_CLASS,
                                     gnc_payment_window_refresh_handler,
                                     gnc_payment_window_close_handler,
                                     pw);
@@ -1222,22 +1361,24 @@ PaymentWindow *
 gnc_ui_payment_new_with_invoice (const GncOwner *owner, QofBook *book,
                                  GncInvoice *invoice)
 {
-    GncOwner owner_def;
     GNCLot *postlot;
-    PreExistTxnInfo *tx_info;
+    InitialPaymentInfo *tx_info;
 
     if (!book) return NULL;
+
+
+    tx_info = g_new0 (InitialPaymentInfo, 1);
+
     if (owner)
     {
         /* Figure out the company */
-        gncOwnerCopy (gncOwnerGetEndOwner (owner), &owner_def);
+        gncOwnerCopy (gncOwnerGetEndOwner (owner), &tx_info->owner);
     }
     else
     {
-        gncOwnerInitCustomer (&owner_def, NULL);
+        gncOwnerInitCustomer (&tx_info->owner, NULL);
     }
 
-    tx_info = g_new0 (PreExistTxnInfo, 1);
     tx_info->post_acct = gncInvoiceGetPostedAcc (invoice);
 
     postlot = gncInvoiceGetPostedLot (invoice);
@@ -1248,7 +1389,7 @@ gnc_ui_payment_new_with_invoice (const GncOwner *owner, QofBook *book,
         lot_info->amount = gnc_numeric_zero ();
         tx_info->lots = g_list_prepend (tx_info->lots, lot_info);
     }
-    return new_payment_window (&owner_def, book, tx_info);
+    return new_payment_window (NULL, book, tx_info);
 }
 
 PaymentWindow *
@@ -1498,7 +1639,7 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner,
 {
     Split *payment_split = NULL;
     Account *post_acct = NULL;
-    PreExistTxnInfo *tx_info = NULL;
+    InitialPaymentInfo *tx_info = NULL;
     GList *txn_lots = NULL;
     gboolean abort = FALSE;
     PaymentWindow *pw;
@@ -1520,12 +1661,13 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner,
         return NULL;
 
     // Fill in the values from the given txn
-    tx_info = g_new0(PreExistTxnInfo, 1);
+    tx_info = g_new0(InitialPaymentInfo, 1);
     tx_info->txn = txn;
     tx_info->post_acct = post_acct;
     tx_info->lots = txn_lots;
+    gncOwnerCopy (owner, &tx_info->owner);
 
-    pw = new_payment_window (owner,
+    pw = new_payment_window (NULL,
                             qof_instance_get_book(QOF_INSTANCE(txn)),
                             tx_info);
 
diff --git a/gnucash/gnome/gtkbuilder/dialog-payment.glade b/gnucash/gnome/gtkbuilder/dialog-payment.glade
index 8b2ff0e..b946e15 100644
--- a/gnucash/gnome/gtkbuilder/dialog-payment.glade
+++ b/gnucash/gnome/gtkbuilder/dialog-payment.glade
@@ -28,6 +28,28 @@
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
+  <object class="GtkListStore" id="owner_type_combo_model">
+    <columns>
+      <!-- column-name Partner -->
+      <column type="gchararray"/>
+      <!-- column-name PartnerType -->
+      <column type="gint"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Customer</col>
+        <col id="1">0</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Vendor</col>
+        <col id="1">0</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Employee</col>
+        <col id="1">0</col>
+      </row>
+    </data>
+  </object>
   <object class="GtkListStore" id="post_combo_model">
     <columns>
       <!-- column-name gchararray -->
@@ -129,21 +151,40 @@
                         <property name="tooltip_markup">The company associated with this payment.</property>
                         <property name="tooltip_text" translatable="yes">The company associated with this payment.</property>
                         <property name="border_width">3</property>
+                        <property name="spacing">5</property>
                         <child>
-                          <placeholder/>
+                          <object class="GtkComboBox" id="owner_type_combo">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="model">owner_type_combo_model</property>
+                            <property name="active">0</property>
+                            <property name="entry_text_column">0</property>
+                            <property name="id_column">1</property>
+                            <child>
+                              <object class="GtkCellRendererText" id="Partner Type"/>
+                              <attributes>
+                                <attribute name="text">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
                         </child>
                       </object>
                     </child>
                   </object>
                 </child>
                 <child type="label">
-                  <object class="GtkLabel" id="owner_label">
+                  <object class="GtkLabel" id="owner_frame_label">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="has_tooltip">True</property>
                     <property name="tooltip_markup">The company associated with this payment.</property>
                     <property name="tooltip_text" translatable="yes">The company associated with this payment.</property>
-                    <property name="label" translatable="yes">(owner)</property>
+                    <property name="label" translatable="yes">Partner</property>
                     <attributes>
                       <attribute name="weight" value="bold"/>
                     </attributes>

commit cd9c3807c03404f830104bd9726a061c6282fe88
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat Nov 18 17:42:46 2017 +0100

    Assign as payment - when random transaction is selected, reset transaction description to owner
    
    This will make the assigned payment more in line with traditionally created business payments

diff --git a/libgnucash/engine/gncOwner.c b/libgnucash/engine/gncOwner.c
index 1035ef9..c6616c5 100644
--- a/libgnucash/engine/gncOwner.c
+++ b/libgnucash/engine/gncOwner.c
@@ -751,6 +751,8 @@ gncOwnerCreatePaymentLot (const GncOwner *owner, Transaction **preset_txn,
 
     if (txn)
     {
+        xaccTransSetDescription (txn, name ? name : "");
+
         /* Pre-existing transaction was specified. We completely clear it,
          * except for the split in the transfer account, unless the
          * transaction can't be reused (wrong currency, wrong transfer account).

commit ce900d1df30d8767ed6f203998364b83687220b2
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Tue Nov 14 15:20:58 2017 +0100

    Assign as payment - refactor a few code blocks into separate functions
    
    And some tweaks to the message strings displayed in case of uncertainty

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index f01c715..efdc193 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -1307,6 +1307,29 @@ gboolean gnc_ui_payment_is_customer_payment(const Transaction *txn)
 }
 
 // ///////////////
+static char *gen_split_desc (Transaction *txn, Split *split)
+{
+    gnc_numeric value = xaccSplitGetValue(split);
+    Account *xfer_acct = xaccSplitGetAccount(split);
+    char *acct_name = gnc_account_get_full_name (xfer_acct);
+    const char *action = gnc_get_action_num (txn, split);
+    const char *memo = xaccSplitGetMemo (split);
+    const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (xfer_acct, TRUE));
+    char *split_str = NULL;
+
+    if (action && *action && memo && *memo)
+        split_str = g_strdup_printf ("%s: %s (%s, %s)", acct_name, print_amt,
+                                        action, memo);
+    else if((action && *action) || (memo && *memo))
+        split_str = g_strdup_printf ("%s: %s (%s)", acct_name, print_amt,
+                                        action ? action : memo);
+    else
+        split_str = g_strdup_printf ("%s: %s", acct_name, print_amt);
+    g_free (acct_name);
+
+    return split_str;
+}
+
 static Split *select_payment_split (GtkWidget *parent, Transaction *txn)
 {
     GList *payment_splits = xaccTransGetPaymentAcctSplitList (txn);
@@ -1350,23 +1373,7 @@ static Split *select_payment_split (GtkWidget *parent, Transaction *txn)
         {
             GtkWidget *rbutton;
             Split *split = node->data;
-            gnc_numeric value = xaccSplitGetValue(split);
-            Account *xfer_acct = xaccSplitGetAccount(split);
-            char *acct_name = gnc_account_get_full_name (xfer_acct);
-            const char *action = gnc_get_action_num (txn, split);
-            const char *memo = xaccSplitGetMemo (split);
-            const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (xfer_acct, TRUE));
-            char *split_str = NULL;
-
-            if (action && *action && memo && *memo)
-                split_str = g_strdup_printf ("%s: %s (%s, %s)", acct_name, print_amt,
-                                             action, memo);
-            else if((action && *action) || (memo && *memo))
-                split_str = g_strdup_printf ("%s: %s (%s)", acct_name, print_amt,
-                                             action ? action : memo);
-            else
-                split_str = g_strdup_printf ("%s: %s", acct_name, print_amt);
-            g_free (acct_name);
+            char *split_str = gen_split_desc (txn, split);
 
             if (node == payment_splits)
             {
@@ -1379,6 +1386,7 @@ static Split *select_payment_split (GtkWidget *parent, Transaction *txn)
             g_object_set_data(G_OBJECT(rbutton), "split", split);
             gtk_box_pack_start (GTK_BOX(content), rbutton, FALSE, FALSE, 0);
 
+            g_free (split_str);
         }
 
         gtk_dialog_set_default_response (dialog, GTK_BUTTONS_CANCEL);
@@ -1407,42 +1415,24 @@ static Split *select_payment_split (GtkWidget *parent, Transaction *txn)
         return payment_splits->data;
 }
 
-PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner, Transaction *txn)
+static GList *select_txn_lots (GtkWidget *parent, Transaction *txn, Account **post_acct, gboolean *abort)
 {
+    gboolean has_no_lot_apar_splits = FALSE;
     SplitList *post_splits = NULL, *no_lot_post_splits = NULL;
     SplitList *iter;
-    Split *payment_split = NULL;
-    gnc_numeric value;
-    Account *xfer_acct, *post_acct = NULL;
-    PaymentWindow *pw;
-    PreExistTxnInfo *tx_info = NULL;
-    GNCLot *postlot = NULL;
     GList *txn_lots = NULL;
-    gboolean has_no_lot_apar_splits = FALSE;
 
-    if (!txn)
-        return NULL;
-
-    // We require the txn to have one split in an Asset account.
-    if (!xaccTransGetSplitList(txn))
-        return NULL;
-
-    payment_split = select_payment_split (parent, txn);
-    if (!payment_split)
+    /* There's no use in continuing if I can't set the post_acct or abort variables */
+    if (!post_acct || !abort)
         return NULL;
 
-    g_assert(payment_split); // we can rely on this because of the check above
-    value = xaccSplitGetValue(payment_split);
-    xfer_acct = xaccSplitGetAccount(payment_split);
+    *abort = FALSE;
+    *post_acct = NULL;
 
-    /* Get all APAR splits */
-    // Prefer true business split (one that's linked to a lot)
-    post_splits = xaccTransGetAPARAcctSplitList (txn, TRUE); // watch out: Might be NULL
-    if (!post_splits)
-        // No true business split found, try again but this time more relaxed
-        post_splits = xaccTransGetAPARAcctSplitList (txn, FALSE); // watch out: Might be NULL
+    post_splits = xaccTransGetAPARAcctSplitList (txn, FALSE);
     for (iter = post_splits; iter; iter = iter->next)
     {
+        GNCLot *postlot = NULL;
         Split *post_split = iter->data;
         postlot = xaccSplitGetLot (post_split);
         if (postlot)
@@ -1451,56 +1441,84 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner,
             lot_info->lot = postlot;
             lot_info->amount = xaccSplitGetValue (post_split);
             txn_lots = g_list_prepend (txn_lots, lot_info);
-            post_acct = xaccSplitGetAccount (post_split);
+            *post_acct = xaccSplitGetAccount (post_split);
         }
         else
         {
             /* Make sure not to override post_acct if it was set above from a lot split */
-            if (!post_acct)
-                post_acct = xaccSplitGetAccount (post_split);
+            if (!*post_acct)
+                *post_acct = xaccSplitGetAccount (post_split);
             no_lot_post_splits = g_list_prepend (no_lot_post_splits, post_split);
             has_no_lot_apar_splits = TRUE;
         }
     }
 
-    /* If the APAR has both splits linked to a business lot and
+    /* If the txn has both APAR splits linked to a business lot and
      * splits that are not, issue a warning some will be discarded.
      */
     if (has_no_lot_apar_splits && (g_list_length (txn_lots) > 0))
     {
         GtkWidget *dialog;
-        int answer = GTK_BUTTONS_OK;
         char *split_str = g_strdup ("");
         for (iter = no_lot_post_splits; iter; iter = iter->next)
         {
             Split *post_split = iter->data;
-            Account *acct = xaccSplitGetAccount(post_split);
-            const char *acct_name = xaccAccountGetName (acct);
-            const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (acct, TRUE));
-            char *tmp_str = g_strdup_printf("%s%s: %s (%s)\n", split_str, acct_name, print_amt,
-                                            gnc_get_action_num (txn, post_split));
+            char *tmp_str = gen_split_desc (txn, post_split);
+            char *tmp_str2 = g_strconcat(split_str, "• ", tmp_str, "\n", NULL);
+            g_free (tmp_str);
             g_free (split_str);
-            split_str = tmp_str;
+            split_str = tmp_str2;
         }
 
         dialog = gtk_message_dialog_new (GTK_WINDOW(parent),
                                          GTK_DIALOG_DESTROY_WITH_PARENT,
                                          GTK_MESSAGE_WARNING,
                                          GTK_BUTTONS_CANCEL,
-                                         _("The transaction has at least one split in a business account that is not part a business transaction.\n"
+                                         _("The transaction has at least one split in a business account that is not part of a business transaction.\n"
                                          "If you continue these splits will be ignored:\n\n%s\n"
                                          "Do you wish to continue and ignore these splits ?"),
                                          split_str);
         gtk_dialog_add_buttons (GTK_DIALOG(dialog),
                                 _("Continue"), GTK_BUTTONS_OK, NULL);
         gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_BUTTONS_CANCEL);
-        answer = gtk_dialog_run (GTK_DIALOG(dialog));
+        if (gtk_dialog_run (GTK_DIALOG(dialog)) != GTK_BUTTONS_OK)
+        {
+            *abort = TRUE;
+            g_list_free_full (txn_lots, g_free);
+            txn_lots = NULL;
+        }
         gtk_widget_destroy (dialog);
         g_free (split_str);
-        if (answer != GTK_BUTTONS_OK)
-            return NULL;
     }
 
+    return txn_lots;
+}
+
+PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner, Transaction *txn)
+{
+    Split *payment_split = NULL;
+    Account *post_acct = NULL;
+    PreExistTxnInfo *tx_info = NULL;
+    GList *txn_lots = NULL;
+    gboolean abort = FALSE;
+    PaymentWindow *pw;
+
+    if (!txn)
+        return NULL;
+
+    // We require the txn to have one split in an Asset account.
+    if (!xaccTransGetSplitList(txn))
+        return NULL;
+
+    payment_split = select_payment_split (parent, txn);
+    if (!payment_split)
+        return NULL;
+
+    /* Get all APAR related lots. Watch out: there might be none */
+    txn_lots = select_txn_lots (parent, txn, &post_acct, &abort);
+    if (abort)
+        return NULL;
+
     // Fill in the values from the given txn
     tx_info = g_new0(PreExistTxnInfo, 1);
     tx_info->txn = txn;
@@ -1517,7 +1535,7 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner,
         GDate txn_date = xaccTransGetDatePostedGDate (txn);
         gnc_ui_payment_window_set_date(pw, &txn_date);
     }
-    gnc_ui_payment_window_set_amount(pw, value);
-    gnc_ui_payment_window_set_xferaccount(pw, xfer_acct);
+    gnc_ui_payment_window_set_amount(pw, xaccSplitGetValue(payment_split));
+    gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(payment_split));
     return pw;
 }

commit d66469fef8b49d038256f07a1642867ce65e200c
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Tue Nov 14 11:17:53 2017 +0100

    Assign as payment - Differentiate between new and existing payments for 'Assign as payment'
    
    When the selected transaction is already involved in a business payment,
    propose to Edit the payment instead of Assigning it as a payment.
    This is more informative and will help prevent users from accidentally replacing existing payments.

diff --git a/gnucash/gnome/gnc-plugin-business.c b/gnucash/gnome/gnc-plugin-business.c
index 32d3132..5b1efca 100644
--- a/gnucash/gnome/gnc-plugin-business.c
+++ b/gnucash/gnome/gnc-plugin-business.c
@@ -319,6 +319,11 @@ static GtkActionEntry gnc_plugin_actions [] =
         N_("Assign the selected transaction as payment"),
         G_CALLBACK (gnc_plugin_business_cmd_assign_payment)
     },
+    {
+        "RegisterEditPayment", NULL, N_("Edit payment..."), NULL,
+        N_("Edit the payment this transaction is a part of"),
+        G_CALLBACK (gnc_plugin_business_cmd_assign_payment)
+    },
 };
 static guint gnc_plugin_n_actions = G_N_ELEMENTS (gnc_plugin_actions);
 
@@ -888,12 +893,18 @@ static const gchar *register_txn_actions[] =
     NULL
 };
 
+static const gchar *register_bus_txn_actions[] =
+{
+    "RegisterEditPayment",
+    NULL
+};
+
 static void
 gnc_plugin_business_update_menus (GncPluginPage *plugin_page)
 {
     GncMainWindow  *window;
     GtkActionGroup *action_group;
-    gboolean is_txn_register;
+    gboolean is_txn_register, is_bus_txn = FALSE;
 
     // We continue only if the current page is a plugin page
     if (!plugin_page || !GNC_IS_PLUGIN_PAGE(plugin_page))
@@ -905,11 +916,21 @@ gnc_plugin_business_update_menus (GncPluginPage *plugin_page)
     action_group = gnc_main_window_get_action_group(window, PLUGIN_ACTIONS_NAME);
     g_return_if_fail(GTK_IS_ACTION_GROUP(action_group));
 
+    if (is_txn_register)
+    {
+        Transaction *trans = gnc_plugin_page_register_get_current_txn (GNC_PLUGIN_PAGE_REGISTER(plugin_page));
+        if (xaccTransCountSplits(trans) > 0)
+            is_bus_txn = (xaccTransGetFirstAPARAcctSplit(trans, TRUE) != NULL);
+    }
     // Change visibility and also sensitivity according to whether we are in a txn register
     gnc_plugin_update_actions (action_group, register_txn_actions,
-                               "sensitive", is_txn_register);
+                               "sensitive", is_txn_register && !is_bus_txn);
     gnc_plugin_update_actions (action_group, register_txn_actions,
-                               "visible", is_txn_register);
+                               "visible", is_txn_register && !is_bus_txn);
+    gnc_plugin_update_actions (action_group, register_bus_txn_actions,
+                               "sensitive", is_txn_register && is_bus_txn);
+    gnc_plugin_update_actions (action_group, register_bus_txn_actions,
+                               "visible", is_txn_register && is_bus_txn);
 }
 
 
@@ -921,6 +942,12 @@ static void gnc_plugin_business_main_window_page_changed(GncMainWindow *window,
     update_inactive_actions(page);
 }
 
+
+void gnc_plugin_business_split_reg_ui_update (GncPluginPage *plugin_page)
+{
+    gnc_plugin_business_main_window_page_changed(NULL, plugin_page, NULL);
+}
+
 static void
 gnc_plugin_business_cmd_test_init_data (GtkAction *action,
                                         GncMainWindowActionData *data)
@@ -1011,6 +1038,7 @@ static const gchar* readonly_inactive_actions[] =
     "EmployeeProcessPaymentAction",
     "ToolbarNewInvoiceAction",
     "RegisterAssignPayment",
+    "RegisterEditPayment",
     NULL
 };
 
diff --git a/gnucash/gnome/gnc-plugin-business.h b/gnucash/gnome/gnc-plugin-business.h
index fe7f9d5..9a0e72c 100644
--- a/gnucash/gnome/gnc-plugin-business.h
+++ b/gnucash/gnome/gnc-plugin-business.h
@@ -66,4 +66,8 @@ void gnc_invoice_remind_bills_due_cb (void);
 void gnc_invoice_remind_invoices_due_cb (void);
 const char *gnc_plugin_business_get_invoice_printreport(void);
 
+
+void gnc_plugin_business_split_reg_ui_update (GncPluginPage *plugin_page);
+
+
 #endif /* __GNC_PLUGIN_BUSINESS_H */
diff --git a/gnucash/gnome/gnc-plugin-page-register.c b/gnucash/gnome/gnc-plugin-page-register.c
index c34dbb9..d0cab8e 100644
--- a/gnucash/gnome/gnc-plugin-page-register.c
+++ b/gnucash/gnome/gnc-plugin-page-register.c
@@ -48,6 +48,7 @@
 #include "gnc-plugin-register.h"
 #include "gnc-plugin-menu-additions.h"
 #include "gnc-plugin-page-report.h"
+#include "gnc-plugin-business.h"
 
 #include "dialog-account.h"
 #include "dialog-find-account.h"
@@ -823,6 +824,17 @@ gnc_plugin_page_register_get_account (GncPluginPageRegister *page)
     return NULL;
 }
 
+Transaction *
+gnc_plugin_page_register_get_current_txn (GncPluginPageRegister *page)
+{
+    GncPluginPageRegisterPrivate *priv;
+    SplitRegister *reg;
+
+    priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
+    reg = gnc_ledger_display_get_split_register(priv->ledger);
+    return gnc_split_register_get_current_trans(reg);
+}
+
 /* This is the list of actions which are switched inactive in a read-only book. */
 static const char* readonly_inactive_actions[] =
 {
@@ -949,10 +961,9 @@ gnc_plugin_page_register_ui_update (gpointer various, GncPluginPageRegister *pag
     uri = xaccTransGetAssociation(trans);
     action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
                                          "ExecAssociatedTransactionAction");
-    if (g_strcmp0 (uri, "") != 0 && g_strcmp0 (uri, NULL) != 0)
-        gtk_action_set_sensitive (GTK_ACTION(action), TRUE);
-    else
-        gtk_action_set_sensitive (GTK_ACTION(action), FALSE);
+    gtk_action_set_sensitive (GTK_ACTION(action), (uri && *uri));
+
+    gnc_plugin_business_split_reg_ui_update (GNC_PLUGIN_PAGE(page));
 
     /* If we are in a readonly book, make any modifying action inactive */
     if (qof_book_is_readonly(gnc_get_current_book()))
diff --git a/gnucash/gnome/gnc-plugin-page-register.h b/gnucash/gnome/gnc-plugin-page-register.h
index 23af07f..43b2b2e 100644
--- a/gnucash/gnome/gnc-plugin-page-register.h
+++ b/gnucash/gnome/gnc-plugin-page-register.h
@@ -153,6 +153,16 @@ gnc_plugin_page_register_get_query (GncPluginPage *plugin_page);
 Account *
 gnc_plugin_page_register_get_account (GncPluginPageRegister *page);
 
+/** Get the currently selected transaction in this register page.
+ *
+ *  @param page A "register" page.
+ *
+ *  @return The currently active transaction or NULL if there currently
+ *  is no currently selected.
+ */
+Transaction *
+gnc_plugin_page_register_get_current_txn (GncPluginPageRegister *page);
+
 G_END_DECLS
 /** @} */
 /** @} */
diff --git a/gnucash/gnome/ui/gnc-plugin-business-ui.xml b/gnucash/gnome/ui/gnc-plugin-business-ui.xml
index 313b23f..b29d897 100644
--- a/gnucash/gnome/ui/gnc-plugin-business-ui.xml
+++ b/gnucash/gnome/ui/gnc-plugin-business-ui.xml
@@ -2,7 +2,8 @@
   <menubar>
     <menu name="Edit" action="EditAction">
       <placeholder name="EditSelectedPlaceholder">
-        <menuitem name="RegisterAssignPayment"       action="RegisterAssignPayment"/>
+          <menuitem name="RegisterAssignPayment"       action="RegisterAssignPayment"/>
+          <menuitem name="RegisterEditPayment"       action="RegisterEditPayment"/>
       </placeholder>
     </menu>
 
@@ -73,7 +74,8 @@
   <popup name="MainPopup" action="FakeToplevel">
     <!--separator name="PopupSep3"/-->
     <placeholder name="PopupPlaceholder3">
-      <menuitem name="RegisterAssignPayment"       action="RegisterAssignPayment"/>
+        <menuitem name="RegisterAssignPayment"       action="RegisterAssignPayment"/>
+        <menuitem name="RegisterEditPayment"       action="RegisterEditPayment"/>
     </placeholder>
   </popup>
 </ui>

commit 18dcbeef8a9ba7213bdd14c7260c8b2d683a0168
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Tue Nov 14 13:56:56 2017 +0100

    Assign as payment - offer possible payment splits to user in case there are multiple valid candidates for assignment

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index aea390a..f01c715 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -1307,27 +1307,9 @@ gboolean gnc_ui_payment_is_customer_payment(const Transaction *txn)
 }
 
 // ///////////////
-
-PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner, Transaction *txn)
+static Split *select_payment_split (GtkWidget *parent, Transaction *txn)
 {
-    SplitList *payment_splits = NULL, *post_splits = NULL, *no_lot_post_splits = NULL;
-    SplitList *iter;
-    gnc_numeric value;
-    Account *xfer_acct, *post_acct = NULL;
-    PaymentWindow *pw;
-    PreExistTxnInfo *tx_info = NULL;
-    GNCLot *postlot = NULL;
-    GList *txn_lots = NULL;
-    gboolean has_no_lot_apar_splits = FALSE;
-
-    if (!txn)
-        return NULL;
-
-    // We require the txn to have one split in an Asset account.
-    if (!xaccTransGetSplitList(txn))
-        return NULL;
-
-    payment_splits = xaccTransGetPaymentAcctSplitList (txn);
+    GList *payment_splits = xaccTransGetPaymentAcctSplitList (txn);
     if (!payment_splits)
     {
 
@@ -1344,33 +1326,114 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner,
         return NULL;
     }
 
-    g_assert(payment_splits->data); // we can rely on this because of the check above
-    value = xaccSplitGetValue(payment_splits->data);
-    xfer_acct = xaccSplitGetAccount(payment_splits->data);
-
     if (g_list_length(payment_splits) > 1)
     {
+        Split *selected_split = NULL;
+        GList *node;
+        GtkWidget *first_rb;
         int answer = GTK_BUTTONS_OK;
-        const char *acct_name = xaccAccountGetName (xfer_acct);
-        const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (xfer_acct, TRUE));
-        GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(parent),
-                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                    GTK_MESSAGE_WARNING,
-                                                    GTK_BUTTONS_CANCEL,
-                                                    _("The transaction has multiple splits that can be considered as 'the payment split'.\n"
-                                                    "If you continue only the following split will be used:\n\n"
-                                                    "%s: %s (%s)\n\n"
-                                                    "Do you wish to continue and ignore the other possible payment splits ?"),
-                                                    acct_name, print_amt,
-                                                    gnc_get_action_num (txn, payment_splits->data));
-        gtk_dialog_add_buttons (GTK_DIALOG(dialog),
-                                _("Continue"), GTK_BUTTONS_OK, NULL);
-        gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_BUTTONS_CANCEL);
-        answer = gtk_dialog_run (GTK_DIALOG(dialog));
-        gtk_widget_destroy (dialog);
-        if (answer != GTK_BUTTONS_OK)
-            return NULL;
+        const char *message = _("While this transaction has multiple splits that can be considered\nas 'the payment split', gnucash only knows how to handle one.\n"
+                                "Please select one, the others will be ignored.\n\n");
+        GtkDialog *dialog = GTK_DIALOG(
+                            gtk_dialog_new_with_buttons (_("Warning"),
+                                                         GTK_WINDOW(parent),
+                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                         _("Continue"), GTK_BUTTONS_OK,
+                                                         _("Cancel"), GTK_BUTTONS_CANCEL,
+                                                         NULL));
+        GtkWidget *content = gtk_dialog_get_content_area(dialog);
+        GtkWidget *label = gtk_label_new (message);
+        gtk_box_pack_start (GTK_BOX(content), label, FALSE, TRUE, 0);
+
+        /* Add splits as selectable options to the dialog */
+        for (node = payment_splits; node; node = node->next)
+        {
+            GtkWidget *rbutton;
+            Split *split = node->data;
+            gnc_numeric value = xaccSplitGetValue(split);
+            Account *xfer_acct = xaccSplitGetAccount(split);
+            char *acct_name = gnc_account_get_full_name (xfer_acct);
+            const char *action = gnc_get_action_num (txn, split);
+            const char *memo = xaccSplitGetMemo (split);
+            const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (xfer_acct, TRUE));
+            char *split_str = NULL;
+
+            if (action && *action && memo && *memo)
+                split_str = g_strdup_printf ("%s: %s (%s, %s)", acct_name, print_amt,
+                                             action, memo);
+            else if((action && *action) || (memo && *memo))
+                split_str = g_strdup_printf ("%s: %s (%s)", acct_name, print_amt,
+                                             action ? action : memo);
+            else
+                split_str = g_strdup_printf ("%s: %s", acct_name, print_amt);
+            g_free (acct_name);
+
+            if (node == payment_splits)
+            {
+                first_rb = gtk_radio_button_new_with_label (NULL, split_str);
+                rbutton = first_rb;
+            }
+            else
+                rbutton = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_rb), split_str);
+
+            g_object_set_data(G_OBJECT(rbutton), "split", split);
+            gtk_box_pack_start (GTK_BOX(content), rbutton, FALSE, FALSE, 0);
+
+        }
+
+        gtk_dialog_set_default_response (dialog, GTK_BUTTONS_CANCEL);
+        gtk_widget_show_all (GTK_WIDGET(dialog));
+        answer = gtk_dialog_run (dialog);
+
+        if (answer == GTK_BUTTONS_OK)
+        {
+            GSList *rbgroup = gtk_radio_button_get_group(GTK_RADIO_BUTTON(first_rb));
+            GSList *rbnode;
+            for (rbnode = rbgroup; rbnode; rbnode = rbnode->next)
+            {
+                GtkWidget *rbutton = rbnode->data;
+                if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutton)))
+                {
+                    selected_split = g_object_get_data(G_OBJECT(rbutton), "split");
+                    break;
+                }
+            }
+        }
+
+        gtk_widget_destroy (GTK_WIDGET(dialog));
+        return selected_split;
     }
+    else
+        return payment_splits->data;
+}
+
+PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner, Transaction *txn)
+{
+    SplitList *post_splits = NULL, *no_lot_post_splits = NULL;
+    SplitList *iter;
+    Split *payment_split = NULL;
+    gnc_numeric value;
+    Account *xfer_acct, *post_acct = NULL;
+    PaymentWindow *pw;
+    PreExistTxnInfo *tx_info = NULL;
+    GNCLot *postlot = NULL;
+    GList *txn_lots = NULL;
+    gboolean has_no_lot_apar_splits = FALSE;
+
+    if (!txn)
+        return NULL;
+
+    // We require the txn to have one split in an Asset account.
+    if (!xaccTransGetSplitList(txn))
+        return NULL;
+
+    payment_split = select_payment_split (parent, txn);
+    if (!payment_split)
+        return NULL;
+
+    g_assert(payment_split); // we can rely on this because of the check above
+    value = xaccSplitGetValue(payment_split);
+    xfer_acct = xaccSplitGetAccount(payment_split);
 
     /* Get all APAR splits */
     // Prefer true business split (one that's linked to a lot)
@@ -1448,7 +1511,7 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner,
                             qof_instance_get_book(QOF_INSTANCE(txn)),
                             tx_info);
 
-    gnc_ui_payment_window_set_num(pw, gnc_get_num_action (txn, payment_splits->data));
+    gnc_ui_payment_window_set_num(pw, gnc_get_num_action (txn, payment_split));
     gnc_ui_payment_window_set_memo(pw, xaccTransGetDescription(txn));
     {
         GDate txn_date = xaccTransGetDatePostedGDate (txn);

commit aeb80a230e3cf0929c1251f110ad69bf81a13f74
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Thu Nov 9 22:56:52 2017 +0100

    Bug 734865 - Assign as Payment... can silently 'unpay' a payed invoice
    
    With this commit the 'assign as payment' logic now works as follows:
    - if the selected transaction is already linked to an existing payment, the payment dialog
      will present this payment again (same partner, post-to account, same selected document(s),
      same amount, memo, and transfer account).
    - if the selected transaction is not linked to an existing business transaction the logic
      will make a best guess as to whether the payment should be for a customer or vendor.
    - in both situations if the existing transaction has multiple splits that can be considered
      as transfer (or 'payment') splits the payment  dialog can't work with it (it can only deal
      with one transfer split). In this case the user will be informed that only one valid
      transfer split will be retained and the others ignored.
    - the other thing the payment dialog can't handle are APAR type splits that are not associated
      to a lot at all. In case of transactions not part of a business transaction they will be
      silently ignored on the assumptions these were manually entered transactions with the intention
      to be linked to business transactions. On the other hand if such a split is part of a transaction
      that is also linked to a business payment already, a warning will be issued these splits will
      be removed from the new payment.

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index a2408f5..aea390a 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -57,6 +57,19 @@
 #define DIALOG_PAYMENT_CUSTOMER_CM_CLASS "customer-payment-dialog"
 #define DIALOG_PAYMENT_VENDOR_CM_CLASS "vendor-payment-dialog"
 
+typedef struct
+{
+    GNCLot      * lot;
+    gnc_numeric   amount;
+} PreExistLotInfo;
+
+typedef struct
+{
+    Transaction * txn;
+    Account     * post_acct;
+    GList       * lots;
+} PreExistTxnInfo;
+
 struct _payment_window
 {
     GtkWidget   * dialog;
@@ -78,14 +91,13 @@ struct _payment_window
     gint          component_id;
     QofBook     * book;
     GncOwner      owner;
-    GncInvoice  * invoice;
     Account     * post_acct;
     Account     * xfer_acct;
     gnc_numeric   amount_tot;
     GList       * acct_types;
     GList       * acct_commodities;
 
-    Transaction * pre_existing_txn;
+    PreExistTxnInfo *tx_info;
     gboolean      print_check_state;
 };
 
@@ -164,7 +176,7 @@ void gnc_ui_payment_window_set_xferaccount (PaymentWindow *pw, const Account* ac
 
 static gboolean gnc_payment_dialog_has_pre_existing_txn(const PaymentWindow* pw)
 {
-    return pw->pre_existing_txn != NULL;
+    return pw->tx_info->txn != NULL;
 }
 int  gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data);
 void gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer data);
@@ -334,52 +346,61 @@ gnc_payment_dialog_document_selection_changed (PaymentWindow *pw)
     gnc_ui_payment_window_set_amount(pw, val);
 }
 
+static gint
+_gnc_lotinfo_find_by_lot(PreExistLotInfo *lotinfo_inst, GNCLot *lot_to_find)
+{
+    if (lotinfo_inst->lot == lot_to_find)
+        return 0;
+    return -1;
+}
+
 static void
-gnc_payment_dialog_highlight_document (PaymentWindow *pw)
+gnc_payment_dialog_highlight_documents (PaymentWindow *pw)
 {
-    if (pw->invoice)
-    {
-        GtkTreeIter iter;
-        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));
-        gtk_tree_selection_unselect_all (selection);
+    gboolean selection_changed = FALSE;
+    GtkTreeIter iter;
+    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));
+    gtk_tree_selection_unselect_all (selection);
 
-        if (gtk_tree_model_get_iter_first (model, &iter))
+    if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+        do
         {
-            do
-            {
-                GValue value = { 0 };
-                GNCLot *lot;
-                GncInvoice *invoice;
-
-                gtk_tree_model_get_value (model, &iter, 5, &value);
-                lot = (GNCLot *) g_value_get_pointer (&value);
-                g_value_unset (&value);
+            GValue value = { 0 };
+            GNCLot *lot;
+            GList *li_node;
 
-                if (!lot)
-                    continue; /* Lot has been deleted behind our back... */
+            gtk_tree_model_get_value (model, &iter, 5, &value);
+            lot = (GNCLot *) g_value_get_pointer (&value);
+            g_value_unset (&value);
 
-                invoice = gncInvoiceGetInvoiceFromLot (lot);
-                if (!invoice)
-                    continue;
+            if (!lot)
+                continue; /* Lot has been deleted behind our back... */
 
-                if (pw->invoice == invoice)
-                {
-                    gtk_tree_selection_select_iter (selection, &iter);
-                    gnc_payment_dialog_document_selection_changed (pw);
-                }
+            li_node = g_list_find_custom (pw->tx_info->lots, lot,
+                                            (GCompareFunc)_gnc_lotinfo_find_by_lot);
+            if (li_node)
+            {
+                gtk_tree_selection_select_iter (selection, &iter);
+                selection_changed = TRUE;
             }
-            while (gtk_tree_model_iter_next (model, &iter));
         }
+        while (gtk_tree_model_iter_next (model, &iter));
     }
+
+    if (selection_changed)
+        gnc_payment_dialog_document_selection_changed (pw);
 }
 
+
 void
 gnc_payment_window_fill_docs_list (PaymentWindow *pw)
 {
     GtkListStore *store;
     GtkTreeSelection *selection;
     GList *list = NULL, *node;
+    GNCLot *tx_lot = NULL;
 
     g_return_if_fail (pw->docs_list_tree_view && GTK_IS_TREE_VIEW(pw->docs_list_tree_view));
 
@@ -388,6 +409,50 @@ gnc_payment_window_fill_docs_list (PaymentWindow *pw)
         list = xaccAccountFindOpenLots (pw->post_acct, gncOwnerLotMatchOwnerFunc,
                                         &pw->owner, NULL);
 
+    /* If pre-existing transaction's post account equals the selected post account
+     * and we have lots for this transaction then compensate the document list for those.
+     * The presence of such lots indicates the pre-existing transaction is an existing payment that
+     * we are about to replace. So we should make sure this existing payment info can be reselected
+     * by the user (within the practical limits of the payment window*) to redo the same
+     * payment again.
+     * If the txn's lots are closed they are ignored by default so we should explicitly readd
+     * them here.
+     * And for all lots in the pre-existing transaction we need to readd the split amount
+     * for that lot or the existing payment values would not be taken into account.
+     * This will happen further below though.
+     *
+     * Finally all this is only relevant if the lot belongs to the same owner...
+     *
+     * * The practical limits are
+     * - The payment dialog can handle only one transfer split. If the pre-existing
+     *   transaction has more possible candidates, all but the first will be used
+     * - The payment dialog can't handle AR/AP splits that aren't linked to a lot
+     *   in the current post account. Such splits will be ignored as well.
+     * In both cases the user will have been informed before and given the option to abort.
+     */
+    if (pw->tx_info->post_acct == pw->post_acct)
+        for (node = pw->tx_info->lots; node; node = node->next)
+        {
+            PreExistLotInfo *lot_info = node->data;
+            if (!gnc_numeric_zero_p (gnc_lot_get_balance (lot_info->lot)))
+                /* This case will be handled below when the lot is processed as part of the open lots */
+                tx_lot = lot_info->lot;
+            else
+            {
+                GncOwner lotowner;
+                if (!gncOwnerGetOwnerFromLot(lot_info->lot, &lotowner))
+                {
+                    const GncOwner *owner;
+                    const GncInvoice *invoice = gncInvoiceGetInvoiceFromLot(lot_info->lot);
+                    if (invoice)
+                        owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
+                    gncOwnerCopy (owner, &lotowner);
+                }
+                if (gncOwnerEqual(&pw->owner, &lotowner))
+                    list = g_list_prepend (list, lot_info->lot);
+            }
+        }
+
     /* Clear the existing list */
     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
     gtk_tree_selection_unselect_all (selection);
@@ -398,6 +463,7 @@ gnc_payment_window_fill_docs_list (PaymentWindow *pw)
     for (node = list; node; node = node->next)
     {
         GNCLot *lot = node->data;
+        GList *li_node;
         time64 doc_date_time = 0;
         const gchar *doc_type_str = NULL;
         const gchar *doc_id_str   = NULL;
@@ -449,11 +515,26 @@ gnc_payment_window_fill_docs_list (PaymentWindow *pw)
          */
         value = gnc_lot_get_balance (lot);
 
+        /* If this lot is linked to the pre-existing transaction, compensate
+         * its amount so the same pre-existing transaction can be reselected bye the user
+         * (within applicable limits)
+         */
+        li_node = g_list_find_custom (pw->tx_info->lots, lot,
+                                      (GCompareFunc)_gnc_lotinfo_find_by_lot);
+        if (li_node)
+        {
+            PreExistLotInfo *lot_info = li_node->data;
+            value = gnc_numeric_sub(value, lot_info->amount,
+                                    gnc_commodity_get_fraction (xaccAccountGetCommodity (pw->post_acct)),
+                                    GNC_HOW_RND_ROUND_HALF_UP);
+        }
+
         if (gnc_numeric_positive_p (value))
             debit = value;
         else
             credit = gnc_numeric_neg (value);
 
+
         /* Only display non-zero debits/credits */
         if (!gnc_numeric_zero_p (debit))
             doc_deb_str = xaccPrintAmount (debit, gnc_default_print_info (FALSE));
@@ -475,7 +556,7 @@ gnc_payment_window_fill_docs_list (PaymentWindow *pw)
     g_list_free (list);
 
     /* Highlight the preset invoice if it's in the new list */
-    gnc_payment_dialog_highlight_document (pw);
+    gnc_payment_dialog_highlight_documents (pw);
 }
 
 static void
@@ -485,9 +566,6 @@ gnc_payment_dialog_owner_changed (PaymentWindow *pw)
     GncGUID *guid = NULL;
     GncOwner *owner = &pw->owner;
 
-    /* If the owner changed, the initial invoice is no longer valid */
-    pw->invoice = NULL;
-
     /* Now handle the account tree */
     if (gncOwnerIsValid(owner))
         qof_instance_get (qofOwnerGetOwner (owner),
@@ -621,14 +699,14 @@ gnc_payment_dialog_post_to_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer
 
     post_acct = gnc_account_select_combo_get_active (pw->post_combo);
 
-    /* If this invoice really changed, then reset ourselves */
+    /* If this post account really changed, then reset ourselves */
     if (post_acct != pw->post_acct)
     {
         pw->post_acct = post_acct;
         gnc_payment_dialog_post_to_changed(pw);
     }
     else
-        gnc_payment_dialog_highlight_document (pw);
+        gnc_payment_dialog_highlight_documents (pw);
 
     /* Reflect if the payment could complete now */
     gnc_payment_window_check_payment (pw);
@@ -740,7 +818,7 @@ gnc_payment_ok_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
         else
             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->tx_info->txn), selected_lots,
                               pw->post_acct, pw->xfer_acct, pw->amount_tot, exch,
                               ts, memo, num, auto_pay);
     }
@@ -752,7 +830,7 @@ gnc_payment_ok_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
     if (gtk_widget_is_sensitive (pw->print_check) &&
         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(pw->print_check)))
     {
-        Split *split = xaccTransFindSplitByAccount (pw->pre_existing_txn, pw->xfer_acct);
+        Split *split = xaccTransFindSplitByAccount (pw->tx_info->txn, pw->xfer_acct);
         GList *splits = NULL;
         splits = g_list_append(splits, split);
         gnc_ui_print_check_dialog_create(NULL, splits);
@@ -779,6 +857,8 @@ gnc_payment_window_destroy_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 
     g_list_free (pw->acct_types);
     g_list_free (pw->acct_commodities);
+    if (pw->tx_info->lots)
+        g_list_free_full (pw->tx_info->lots, g_free);
     g_free (pw);
 }
 
@@ -880,7 +960,7 @@ static void print_date (G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
 }
 
 static PaymentWindow *
-new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
+new_payment_window (GncOwner *owner, QofBook *book, PreExistTxnInfo *tx_info)
 {
     PaymentWindow *pw;
     GtkBuilder *builder;
@@ -892,10 +972,16 @@ new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
                        DIALOG_PAYMENT_CUSTOMER_CM_CLASS :
                        DIALOG_PAYMENT_VENDOR_CM_CLASS);
 
+    /* Ensure we always have a properly initialized PreExistTxnInfo struct to work with */
+    if (!tx_info)
+    {
+        tx_info = g_new0 (PreExistTxnInfo, 1);
+    }
+
     /*
      * Find an existing payment window.  If found, bring it to
      * the front.  If we have an actual owner, then set it in
-     * the window.
+     * the window. And update the PreExistTxnInfo (tx_info) for this window.
      */
 
     pw = gnc_find_first_gui_component (cm_class, find_handler, NULL);
@@ -904,8 +990,11 @@ new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
         if (gncOwnerIsValid(owner))
             gnc_payment_set_owner (pw, owner);
 
-        // Reset the setting about the pre-existing TXN
-        pw->pre_existing_txn = NULL;
+        // Reset the current
+        if (pw->tx_info->lots)
+            g_list_free_full (pw->tx_info->lots, g_free);
+        g_free (pw->tx_info);
+        pw->tx_info = tx_info;
 
         gtk_window_present (GTK_WINDOW(pw->dialog));
         return(pw);
@@ -915,6 +1004,7 @@ new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
 
     pw = g_new0 (PaymentWindow, 1);
     pw->book = book;
+    pw->tx_info = tx_info;
     gncOwnerCopy (owner, &(pw->owner));
 
     /* Compute the post-to account types */
@@ -1046,19 +1136,9 @@ new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
      * Note that this also sets the post account tree. */
     gnc_payment_dialog_owner_changed(pw);
 
-    /* Set the dialog for the 'new' invoice */
-    pw->invoice = invoice;
-    if (invoice)
-    {
-        Account *postacct = gncInvoiceGetPostedAcc (invoice);
-        if (postacct)
-        {
-            gchar *acct_string = gnc_account_get_full_name (postacct);
-            gnc_cbwe_set_by_string(GTK_COMBO_BOX(pw->post_combo), acct_string);
-            gnc_payment_dialog_post_to_changed_cb (pw->post_combo, pw);
-            g_free(acct_string);
-        }
-    }
+    if (pw->tx_info->post_acct)
+        gnc_ui_payment_window_set_postaccount (pw, tx_info->post_acct);
+    gnc_payment_dialog_post_to_changed_cb (pw->post_combo, pw);
 
     /* Setup signals */
     gtk_builder_connect_signals_full( builder,
@@ -1134,6 +1214,7 @@ void
 gnc_ui_payment_window_destroy (PaymentWindow *pw)
 {
     if (!pw) return;
+
     gnc_close_gui_component (pw->component_id);
 }
 
@@ -1142,6 +1223,8 @@ gnc_ui_payment_new_with_invoice (const GncOwner *owner, QofBook *book,
                                  GncInvoice *invoice)
 {
     GncOwner owner_def;
+    GNCLot *postlot;
+    PreExistTxnInfo *tx_info;
 
     if (!book) return NULL;
     if (owner)
@@ -1154,7 +1237,18 @@ gnc_ui_payment_new_with_invoice (const GncOwner *owner, QofBook *book,
         gncOwnerInitCustomer (&owner_def, NULL);
     }
 
-    return new_payment_window (&owner_def, book, invoice);
+    tx_info = g_new0 (PreExistTxnInfo, 1);
+    tx_info->post_acct = gncInvoiceGetPostedAcc (invoice);
+
+    postlot = gncInvoiceGetPostedLot (invoice);
+    if (postlot)
+    {
+        PreExistLotInfo *lot_info = g_new0 (PreExistLotInfo, 1);
+        lot_info->lot = postlot;
+        lot_info->amount = gnc_numeric_zero ();
+        tx_info->lots = g_list_prepend (tx_info->lots, lot_info);
+    }
+    return new_payment_window (&owner_def, book, tx_info);
 }
 
 PaymentWindow *
@@ -1216,21 +1310,25 @@ gboolean gnc_ui_payment_is_customer_payment(const Transaction *txn)
 
 PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner, Transaction *txn)
 {
-    Split *assetaccount_split;
-    Split *postaccount_split;
-    gnc_numeric amount;
+    SplitList *payment_splits = NULL, *post_splits = NULL, *no_lot_post_splits = NULL;
+    SplitList *iter;
+    gnc_numeric value;
+    Account *xfer_acct, *post_acct = NULL;
     PaymentWindow *pw;
+    PreExistTxnInfo *tx_info = NULL;
+    GNCLot *postlot = NULL;
+    GList *txn_lots = NULL;
+    gboolean has_no_lot_apar_splits = FALSE;
 
     if (!txn)
         return NULL;
 
     // We require the txn to have one split in an Asset account.
-
     if (!xaccTransGetSplitList(txn))
         return NULL;
 
-    assetaccount_split = xaccTransGetFirstPaymentAcctSplit(txn);
-    if (!assetaccount_split)
+    payment_splits = xaccTransGetPaymentAcctSplitList (txn);
+    if (!payment_splits)
     {
 
         GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(parent),
@@ -1246,30 +1344,117 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner,
         return NULL;
     }
 
+    g_assert(payment_splits->data); // we can rely on this because of the check above
+    value = xaccSplitGetValue(payment_splits->data);
+    xfer_acct = xaccSplitGetAccount(payment_splits->data);
+
+    if (g_list_length(payment_splits) > 1)
+    {
+        int answer = GTK_BUTTONS_OK;
+        const char *acct_name = xaccAccountGetName (xfer_acct);
+        const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (xfer_acct, TRUE));
+        GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(parent),
+                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                    GTK_MESSAGE_WARNING,
+                                                    GTK_BUTTONS_CANCEL,
+                                                    _("The transaction has multiple splits that can be considered as 'the payment split'.\n"
+                                                    "If you continue only the following split will be used:\n\n"
+                                                    "%s: %s (%s)\n\n"
+                                                    "Do you wish to continue and ignore the other possible payment splits ?"),
+                                                    acct_name, print_amt,
+                                                    gnc_get_action_num (txn, payment_splits->data));
+        gtk_dialog_add_buttons (GTK_DIALOG(dialog),
+                                _("Continue"), GTK_BUTTONS_OK, NULL);
+        gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_BUTTONS_CANCEL);
+        answer = gtk_dialog_run (GTK_DIALOG(dialog));
+        gtk_widget_destroy (dialog);
+        if (answer != GTK_BUTTONS_OK)
+            return NULL;
+    }
+
+    /* Get all APAR splits */
     // Prefer true business split (one that's linked to a lot)
-    postaccount_split = xaccTransGetFirstAPARAcctSplit(txn, TRUE); // watch out: Might be NULL
-    if (!postaccount_split)
+    post_splits = xaccTransGetAPARAcctSplitList (txn, TRUE); // watch out: Might be NULL
+    if (!post_splits)
         // No true business split found, try again but this time more relaxed
-        postaccount_split = xaccTransGetFirstAPARAcctSplit(txn, FALSE); // watch out: Might be NULL
-    amount = xaccSplitGetValue(assetaccount_split);
+        post_splits = xaccTransGetAPARAcctSplitList (txn, FALSE); // watch out: Might be NULL
+    for (iter = post_splits; iter; iter = iter->next)
+    {
+        Split *post_split = iter->data;
+        postlot = xaccSplitGetLot (post_split);
+        if (postlot)
+        {
+            PreExistLotInfo *lot_info = g_new0 (PreExistLotInfo, 1);
+            lot_info->lot = postlot;
+            lot_info->amount = xaccSplitGetValue (post_split);
+            txn_lots = g_list_prepend (txn_lots, lot_info);
+            post_acct = xaccSplitGetAccount (post_split);
+        }
+        else
+        {
+            /* Make sure not to override post_acct if it was set above from a lot split */
+            if (!post_acct)
+                post_acct = xaccSplitGetAccount (post_split);
+            no_lot_post_splits = g_list_prepend (no_lot_post_splits, post_split);
+            has_no_lot_apar_splits = TRUE;
+        }
+    }
 
-    pw = gnc_ui_payment_new(owner,
-                            qof_instance_get_book(QOF_INSTANCE(txn)));
-    g_assert(assetaccount_split); // we can rely on this because of the check above
-    g_debug("Amount=%s", gnc_numeric_to_string(amount));
+    /* If the APAR has both splits linked to a business lot and
+     * splits that are not, issue a warning some will be discarded.
+     */
+    if (has_no_lot_apar_splits && (g_list_length (txn_lots) > 0))
+    {
+        GtkWidget *dialog;
+        int answer = GTK_BUTTONS_OK;
+        char *split_str = g_strdup ("");
+        for (iter = no_lot_post_splits; iter; iter = iter->next)
+        {
+            Split *post_split = iter->data;
+            Account *acct = xaccSplitGetAccount(post_split);
+            const char *acct_name = xaccAccountGetName (acct);
+            const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (acct, TRUE));
+            char *tmp_str = g_strdup_printf("%s%s: %s (%s)\n", split_str, acct_name, print_amt,
+                                            gnc_get_action_num (txn, post_split));
+            g_free (split_str);
+            split_str = tmp_str;
+        }
+
+        dialog = gtk_message_dialog_new (GTK_WINDOW(parent),
+                                         GTK_DIALOG_DESTROY_WITH_PARENT,
+                                         GTK_MESSAGE_WARNING,
+                                         GTK_BUTTONS_CANCEL,
+                                         _("The transaction has at least one split in a business account that is not part a business transaction.\n"
+                                         "If you continue these splits will be ignored:\n\n%s\n"
+                                         "Do you wish to continue and ignore these splits ?"),
+                                         split_str);
+        gtk_dialog_add_buttons (GTK_DIALOG(dialog),
+                                _("Continue"), GTK_BUTTONS_OK, NULL);
+        gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_BUTTONS_CANCEL);
+        answer = gtk_dialog_run (GTK_DIALOG(dialog));
+        gtk_widget_destroy (dialog);
+        g_free (split_str);
+        if (answer != GTK_BUTTONS_OK)
+            return NULL;
+    }
 
     // Fill in the values from the given txn
-    pw->pre_existing_txn = txn;
-    gnc_ui_payment_window_set_num(pw, gnc_get_num_action(txn, assetaccount_split));
+    tx_info = g_new0(PreExistTxnInfo, 1);
+    tx_info->txn = txn;
+    tx_info->post_acct = post_acct;
+    tx_info->lots = txn_lots;
+
+    pw = new_payment_window (owner,
+                            qof_instance_get_book(QOF_INSTANCE(txn)),
+                            tx_info);
+
+    gnc_ui_payment_window_set_num(pw, gnc_get_num_action (txn, payment_splits->data));
     gnc_ui_payment_window_set_memo(pw, xaccTransGetDescription(txn));
     {
         GDate txn_date = xaccTransGetDatePostedGDate (txn);
         gnc_ui_payment_window_set_date(pw, &txn_date);
     }
-    gnc_ui_payment_window_set_amount(pw, amount);
-    gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(assetaccount_split));
-    if (postaccount_split)
-        gnc_ui_payment_window_set_postaccount(pw, xaccSplitGetAccount(postaccount_split));
-
+    gnc_ui_payment_window_set_amount(pw, value);
+    gnc_ui_payment_window_set_xferaccount(pw, xfer_acct);
     return pw;
 }

commit 0dfb921e86357df280ded13c7cd1ce9da139f8c4
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Mon Nov 13 19:15:04 2017 +0100

    Add functions to retrieve a copy of splits of a certain type from business transactions

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index c87e949..a2408f5 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -1179,7 +1179,11 @@ gboolean gnc_ui_payment_is_customer_payment(const Transaction *txn)
 
     /* First test if one split is in an A/R or A/P account.
      * That will give us the best Customer vs Vendor/Employee distinction */
-    aparaccount_split = xaccTransGetFirstAPARAcctSplit(txn);
+    // Prefer true business split (one that's linked to a lot)
+    aparaccount_split = xaccTransGetFirstAPARAcctSplit(txn, TRUE);
+    if (!aparaccount_split)
+        // No true business split found, try again but this time more relaxed
+        aparaccount_split = xaccTransGetFirstAPARAcctSplit(txn, FALSE);
     if (aparaccount_split)
     {
         if (xaccAccountGetType (xaccSplitGetAccount (aparaccount_split)) == ACCT_TYPE_RECEIVABLE)
@@ -1242,7 +1246,11 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner,
         return NULL;
     }
 
-    postaccount_split = xaccTransGetFirstAPARAcctSplit(txn); // watch out: Might be NULL
+    // Prefer true business split (one that's linked to a lot)
+    postaccount_split = xaccTransGetFirstAPARAcctSplit(txn, TRUE); // watch out: Might be NULL
+    if (!postaccount_split)
+        // No true business split found, try again but this time more relaxed
+        postaccount_split = xaccTransGetFirstAPARAcctSplit(txn, FALSE); // watch out: Might be NULL
     amount = xaccSplitGetValue(assetaccount_split);
 
     pw = gnc_ui_payment_new(owner,
diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c
index c5d910d..b6c9264 100644
--- a/libgnucash/engine/Transaction.c
+++ b/libgnucash/engine/Transaction.c
@@ -66,6 +66,8 @@ struct timeval
 #include "SchedXaction.h"
 #include "gncBusiness.h"
 #include <qofinstance-p.h>
+#include "gncInvoice.h"
+#include "gncOwner.h"
 
 /* Notes about xaccTransBeginEdit(), xaccTransCommitEdit(), and
  *  xaccTransRollback():
@@ -2241,23 +2243,76 @@ xaccTransGetSplitList (const Transaction *trans)
     return trans ? trans->splits : NULL;
 }
 
+SplitList *
+xaccTransGetPaymentAcctSplitList (const Transaction *trans)
+{
+    GList *pay_splits = NULL;
+    FOR_EACH_SPLIT (trans,
+                    const Account *account = xaccSplitGetAccount(s);
+                    if (account && gncBusinessIsPaymentAcctType(xaccAccountGetType(account)))
+                        pay_splits = g_list_prepend (pay_splits, s);
+    );
+
+    pay_splits = g_list_reverse (pay_splits);
+    return pay_splits;
+}
+
+SplitList *
+xaccTransGetAPARAcctSplitList (const Transaction *trans, gboolean strict)
+{
+    GList *apar_splits = NULL;
+    FOR_EACH_SPLIT (trans,
+                    const Account *account = xaccSplitGetAccount(s);
+                    if (account && xaccAccountIsAPARType(xaccAccountGetType(account)))
+                    {
+
+                        if (!strict)
+                            apar_splits = g_list_prepend (apar_splits, s);
+                        else
+                        {
+                            GncOwner owner;
+                            GNCLot *lot = xaccSplitGetLot(s);
+                            if (lot &&
+                                (gncInvoiceGetInvoiceFromLot (lot) ||
+                                gncOwnerGetOwnerFromLot (lot, &owner)))
+                                apar_splits = g_list_prepend (apar_splits, s);
+                        }
+                    }
+    );
+
+    apar_splits = g_list_reverse (apar_splits);
+    return apar_splits;
+}
+
 Split *xaccTransGetFirstPaymentAcctSplit(const Transaction *trans)
 {
     FOR_EACH_SPLIT (trans,
                     const Account *account = xaccSplitGetAccount(s);
-                    if (gncBusinessIsPaymentAcctType(xaccAccountGetType(account)))
+                    if (account && gncBusinessIsPaymentAcctType(xaccAccountGetType(account)))
                         return s;
                    );
 
     return NULL;
 }
 
-Split *xaccTransGetFirstAPARAcctSplit(const Transaction *trans)
+Split *xaccTransGetFirstAPARAcctSplit (const Transaction *trans, gboolean strict)
 {
     FOR_EACH_SPLIT (trans,
                     const Account *account = xaccSplitGetAccount(s);
-                    if (xaccAccountIsAPARType(xaccAccountGetType(account)))
-                        return s;
+                    if (account && xaccAccountIsAPARType(xaccAccountGetType(account)))
+                    {
+                        GNCLot *lot;
+                        GncOwner owner;
+
+                        if (!strict)
+                            return s;
+
+                        lot = xaccSplitGetLot(s);
+                        if (lot &&
+                            (gncInvoiceGetInvoiceFromLot (lot) ||
+                            gncOwnerGetOwnerFromLot (lot, &owner)))
+                            return s;
+                    }
                    );
 
     return NULL;
diff --git a/libgnucash/engine/Transaction.h b/libgnucash/engine/Transaction.h
index a56a2c6..a196e89 100644
--- a/libgnucash/engine/Transaction.h
+++ b/libgnucash/engine/Transaction.h
@@ -370,10 +370,27 @@ int xaccTransGetSplitIndex(const Transaction *trans, const Split *split);
 
 /** The xaccTransGetSplitList() method returns a GList of the splits
     in a transaction.
+    @param trans The transaction
     @return The list of splits. This list must NOT be modified.  Do *NOT* free
     this list when you are done with it. */
 /*@ dependent @*/
 SplitList *   xaccTransGetSplitList (const Transaction *trans);
+
+/** The xaccTransGetPaymentAcctSplitList() method returns a GList of the splits
+    in a transaction that belong to an account which is considered a
+    valid account for business payments.
+    @param trans The transaction
+    @return The list of splits. This list must be freed when you are done with it. */
+SplitList *   xaccTransGetPaymentAcctSplitList (const Transaction *trans);
+
+/** The xaccTransGetAPARSplitList() method returns a GList of the splits
+    in a transaction that belong to an AR or AP account.
+    @param trans The transaction
+    @param strict This slightly modifies the test to only consider splits in an AR or AP account and the split is part of a business lot
+    @return The list of splits. This list must be freed when you are done with it. */
+SplitList *   xaccTransGetAPARAcctSplitList (const Transaction *trans, gboolean strict);
+
+
 gboolean      xaccTransStillHasSplit(const Transaction *trans, const Split *s);
 
 /** The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first
@@ -387,9 +404,10 @@ Split *       xaccTransGetFirstPaymentAcctSplit (const Transaction *trans);
 /** The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first
     split in this transaction that belongs to an AR or AP account.
     @param trans The transaction
+    @param strict This slightly modifies the test to only consider splits in an AR or AP account and the split is part of a business lot
 
     If there is no such split in the transaction NULL will be returned. */
-Split *       xaccTransGetFirstAPARAcctSplit (const Transaction *trans);
+Split *       xaccTransGetFirstAPARAcctSplit (const Transaction *trans, gboolean strict);
 
 /** Set the transaction to be ReadOnly by setting a non-NULL value as "reason".
  *
diff --git a/libgnucash/engine/gncOwner.c b/libgnucash/engine/gncOwner.c
index af0faee..1035ef9 100644
--- a/libgnucash/engine/gncOwner.c
+++ b/libgnucash/engine/gncOwner.c
@@ -656,7 +656,7 @@ gboolean gncOwnerGetOwnerFromTxn (Transaction *txn, GncOwner *owner)
     if (xaccTransGetTxnType (txn) == TXN_TYPE_NONE)
         return FALSE;
 
-    apar_split = xaccTransGetFirstAPARAcctSplit (txn);
+    apar_split = xaccTransGetFirstAPARAcctSplit (txn, TRUE);
     if (apar_split)
     {
         GNCLot *lot = xaccSplitGetLot (apar_split);

commit de4414b2a100812aa796041d1a87c99d1aa63418
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Thu Nov 9 20:36:54 2017 +0100

    Inform the user when assign as payment can't be used

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index 85300e5..c87e949 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -1210,7 +1210,7 @@ gboolean gnc_ui_payment_is_customer_payment(const Transaction *txn)
 
 // ///////////////
 
-PaymentWindow * gnc_ui_payment_new_with_txn (GncOwner *owner, Transaction *txn)
+PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget* parent, GncOwner *owner, Transaction *txn)
 {
     Split *assetaccount_split;
     Split *postaccount_split;
@@ -1224,9 +1224,19 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GncOwner *owner, Transaction *txn)
 
     if (!xaccTransGetSplitList(txn))
         return NULL;
+
     assetaccount_split = xaccTransGetFirstPaymentAcctSplit(txn);
     if (!assetaccount_split)
     {
+
+        GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(parent),
+                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                    GTK_MESSAGE_INFO,
+                                                    GTK_BUTTONS_CLOSE,
+                                                    "%s",
+                                                    _("The selected transaction doesn't have splits that can be assigned as a payment"));
+        gtk_dialog_run (GTK_DIALOG(dialog));
+        gtk_widget_destroy (dialog);
         g_message("No asset splits in txn \"%s\"; cannot use this for assigning a payment.",
                   xaccTransGetDescription(txn));
         return NULL;
diff --git a/gnucash/gnome/dialog-payment.h b/gnucash/gnome/dialog-payment.h
index d393b16..49113da 100644
--- a/gnucash/gnome/dialog-payment.h
+++ b/gnucash/gnome/dialog-payment.h
@@ -34,7 +34,7 @@ PaymentWindow * gnc_ui_payment_new (GncOwner *owner, QofBook *book);
 PaymentWindow * gnc_ui_payment_new_with_invoice (const GncOwner *owner,
         QofBook *book,
         GncInvoice *invoice);
-PaymentWindow * gnc_ui_payment_new_with_txn (GncOwner *owner, Transaction *txn);
+PaymentWindow * gnc_ui_payment_new_with_txn (GtkWidget *parent, GncOwner *owner, Transaction *txn);
 
 /** Returns TRUE if the given transaction (to be used with gnc_ui_payment_new_with_txn() )
  * is for a customer, or FALSE if it's from a vendor or employee voucher. */
diff --git a/gnucash/gnome/gnc-plugin-business.c b/gnucash/gnome/gnc-plugin-business.c
index a4660c6..32d3132 100644
--- a/gnucash/gnome/gnc-plugin-business.c
+++ b/gnucash/gnome/gnc-plugin-business.c
@@ -827,7 +827,7 @@ static void gnc_business_assign_payment (GtkWidget *parent,
         return;
 
     //g_message("Creating payment dialog with trans %p", trans);
-    gnc_ui_payment_new_with_txn(owner, trans);
+    gnc_ui_payment_new_with_txn(parent, owner, trans);
 }
 
 static void gnc_plugin_business_cmd_assign_payment (GtkAction *action,

commit 954ce1ab118850ec8d8f844698407b697829359a
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Tue Nov 14 14:00:04 2017 +0100

    Mark unused function parameters as such in dialog-payment.c

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index aafa4a5..85300e5 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -180,7 +180,7 @@ void gnc_payment_window_fill_docs_list (PaymentWindow *pw);
 
 
 static void
-gnc_payment_window_refresh_handler (GHashTable *changes, gpointer data)
+gnc_payment_window_refresh_handler (G_GNUC_UNUSED GHashTable *changes, gpointer data)
 {
     PaymentWindow *pw = data;
 
@@ -275,7 +275,7 @@ gnc_payment_window_close_handler (gpointer data)
 
 static void
 calculate_selected_total_helper (GtkTreeModel *model,
-                                 GtkTreePath *path,
+                                 G_GNUC_UNUSED GtkTreePath *path,
                                  GtkTreeIter *iter,
                                  gpointer data)
 {
@@ -564,7 +564,7 @@ gnc_payment_set_owner (PaymentWindow *pw, GncOwner *owner)
 }
 
 static int
-gnc_payment_dialog_owner_changed_cb (GtkWidget *widget, gpointer data)
+gnc_payment_dialog_owner_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
     PaymentWindow *pw = data;
     GncOwner owner;
@@ -588,7 +588,7 @@ gnc_payment_dialog_owner_changed_cb (GtkWidget *widget, gpointer data)
 }
 
 void
-gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer data)
+gnc_payment_dialog_document_selection_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
     PaymentWindow *pw = data;
 
@@ -601,7 +601,7 @@ gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer da
 }
 
 void
-gnc_payment_dialog_xfer_acct_changed_cb (GtkWidget *widget, gpointer data)
+gnc_payment_dialog_xfer_acct_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
     PaymentWindow *pw = data;
 
@@ -612,7 +612,7 @@ gnc_payment_dialog_xfer_acct_changed_cb (GtkWidget *widget, gpointer data)
 }
 
 int
-gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data)
+gnc_payment_dialog_post_to_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
     PaymentWindow *pw = data;
     Account *post_acct;
@@ -643,7 +643,7 @@ gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data)
  */
 static void
 get_selected_lots (GtkTreeModel *model,
-                   GtkTreePath *path,
+                   G_GNUC_UNUSED GtkTreePath *path,
                    GtkTreeIter *iter,
                    gpointer data)
 {
@@ -660,7 +660,7 @@ get_selected_lots (GtkTreeModel *model,
 }
 
 void
-gnc_payment_ok_cb (GtkWidget *widget, gpointer data)
+gnc_payment_ok_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
     PaymentWindow *pw = data;
     const char *text = NULL;
@@ -762,14 +762,14 @@ gnc_payment_ok_cb (GtkWidget *widget, gpointer data)
 }
 
 void
-gnc_payment_cancel_cb (GtkWidget *widget, gpointer data)
+gnc_payment_cancel_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
     PaymentWindow *pw = data;
     gnc_ui_payment_window_destroy (pw);
 }
 
 void
-gnc_payment_window_destroy_cb (GtkWidget *widget, gpointer data)
+gnc_payment_window_destroy_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
 {
     PaymentWindow *pw = data;
 
@@ -784,7 +784,7 @@ gnc_payment_window_destroy_cb (GtkWidget *widget, gpointer data)
 
 void
 gnc_payment_acct_tree_row_activated_cb (GtkWidget *widget, GtkTreePath *path,
-                                        GtkTreeViewColumn *column, PaymentWindow *pw)
+                                        G_GNUC_UNUSED GtkTreeViewColumn *column, PaymentWindow *pw)
 {
     GtkTreeView *view;
     GtkTreeModel *model;
@@ -813,7 +813,8 @@ gnc_payment_acct_tree_row_activated_cb (GtkWidget *widget, GtkTreePath *path,
 }
 
 void
-gnc_payment_leave_amount_cb (GtkWidget *widget, GdkEventFocus *event,
+gnc_payment_leave_amount_cb (G_GNUC_UNUSED GtkWidget *widget,
+                             G_GNUC_UNUSED GdkEventFocus *event,
                              PaymentWindow *pw)
 {
     gnc_numeric amount_deb, amount_cred, amount_tot;
@@ -850,18 +851,18 @@ gnc_payment_set_account_types (GncTreeViewAccount *tree)
 }
 
 static gboolean
-find_handler (gpointer find_data, gpointer user_data)
+find_handler (G_GNUC_UNUSED gpointer find_data, gpointer user_data)
 {
     PaymentWindow *pw = user_data;
 
     return (pw != NULL);
 }
 
-static void print_date (GtkTreeViewColumn *tree_column,
+static void print_date (G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
                         GtkCellRenderer *cell,
                         GtkTreeModel *tree_model,
                         GtkTreeIter *iter,
-                        gpointer data)
+                        G_GNUC_UNUSED gpointer data)
 {
     GValue value = { 0 };
     time64 doc_date_time;



Summary of changes:
 gnucash/gnome/dialog-payment.c                | 777 ++++++++++++++++++++------
 gnucash/gnome/dialog-payment.h                |   2 +-
 gnucash/gnome/gnc-plugin-business.c           |  36 +-
 gnucash/gnome/gnc-plugin-business.h           |   4 +
 gnucash/gnome/gnc-plugin-page-register.c      |  19 +-
 gnucash/gnome/gnc-plugin-page-register.h      |  10 +
 gnucash/gnome/gtkbuilder/dialog-payment.glade |  47 +-
 gnucash/gnome/ui/gnc-plugin-business-ui.xml   |   6 +-
 libgnucash/engine/Transaction.c               |  63 ++-
 libgnucash/engine/Transaction.h               |  20 +-
 libgnucash/engine/gncOwner.c                  |   4 +-
 11 files changed, 793 insertions(+), 195 deletions(-)



More information about the gnucash-changes mailing list