r21382 - gnucash/trunk/src/business/business-gnome - Extend "Process Payment" dialog so that it accepts an existing transaction as well, and marks this as payment.

Christian Stimming cstim at code.gnucash.org
Fri Oct 7 17:49:57 EDT 2011


Author: cstim
Date: 2011-10-07 17:49:56 -0400 (Fri, 07 Oct 2011)
New Revision: 21382
Trac: http://svn.gnucash.org/trac/changeset/21382

Modified:
   gnucash/trunk/src/business/business-gnome/dialog-payment.c
   gnucash/trunk/src/business/business-gnome/dialog-payment.h
Log:
Extend "Process Payment" dialog so that it accepts an existing transaction as well, and marks this as payment.

Modified: gnucash/trunk/src/business/business-gnome/dialog-payment.c
===================================================================
--- gnucash/trunk/src/business/business-gnome/dialog-payment.c	2011-10-07 12:21:41 UTC (rev 21381)
+++ gnucash/trunk/src/business/business-gnome/dialog-payment.c	2011-10-07 21:49:56 UTC (rev 21382)
@@ -70,9 +70,54 @@
     GncInvoice *	invoice;
     GList *	acct_types;
     GList *       acct_commodities;
+
+    Transaction *pre_existing_txn;
 };
 
+void gnc_ui_payment_window_set_num (PaymentWindow *pw, const char* num)
+{
+    g_assert(pw);
+    gtk_entry_set_text(GTK_ENTRY (pw->num_entry), num);
+}
+void gnc_ui_payment_window_set_memo (PaymentWindow *pw, const char* memo)
+{
+    g_assert(pw);
+    gtk_entry_set_text(GTK_ENTRY (pw->memo_entry), memo);
+}
+void gnc_ui_payment_window_set_date (PaymentWindow *pw, const GDate *date)
+{
+    g_assert(pw);
+    g_assert(date);
+    gnc_date_edit_set_gdate (GNC_DATE_EDIT (pw->date_edit), date);
+}
+void gnc_ui_payment_window_set_amount (PaymentWindow *pw, gnc_numeric amount)
+{
+    g_assert(pw);
+    gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_edit), amount);
+}
+void gnc_ui_payment_window_set_postaccount (PaymentWindow *pw, const Account* account)
+{
+    g_assert(pw);
+    g_assert(account);
+    {
+        gchar *acct_string = gnc_account_get_full_name (account);
+        gnc_cbe_set_by_string(GTK_COMBO_BOX_ENTRY(pw->post_combo), acct_string);
+        g_free(acct_string);
+    }
+}
+void gnc_ui_payment_window_set_xferaccount (PaymentWindow *pw, const Account* account)
+{
+    g_assert(pw);
+    g_assert(account);
+    gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
+            (Account*)account);
+}
 
+static gboolean has_pre_existing_txn(const PaymentWindow* pw)
+{
+    return pw->pre_existing_txn != NULL;
+}
+
 void gnc_payment_ok_cb (GtkWidget *widget, gpointer data);
 void gnc_payment_cancel_cb (GtkWidget *widget, gpointer data);
 void gnc_payment_window_destroy_cb (GtkWidget *widget, gpointer data);
@@ -103,6 +148,11 @@
     GNCLot *lot;
     gnc_numeric val;
 
+    // Ignore the amount of the invoice in case this payment is from a
+    // pre-existing txn
+    if (has_pre_existing_txn(pw))
+        return;
+
     /* Set the payment amount in the dialog */
     if (pw->invoice)
     {
@@ -114,7 +164,7 @@
         val = gnc_numeric_zero();
     }
 
-    gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_edit), val);
+    gnc_ui_payment_window_set_amount(pw, val);
 }
 
 static void
@@ -170,8 +220,9 @@
         last_acct = xaccAccountLookup(guid, pw->book);
     }
 
-    /* Set the last-used transfer account */
-    if (last_acct)
+    /* Set the last-used transfer account, but only if we didn't
+     * create this dialog from a pre-existing transaction. */
+    if (last_acct && !has_pre_existing_txn(pw))
     {
         gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
                 last_acct);
@@ -341,10 +392,64 @@
             gnc_xfer_dialog_run_until_done(xfer);
         }
 
-        /* Now apply the payment */
-        gncOwnerApplyPayment (&pw->owner, pw->invoice,
-                              post, acc, amount, exch, date, memo, num);
+        if (!has_pre_existing_txn(pw))
+        {
+            /* Now apply the payment */
+            gncOwnerApplyPayment (&pw->owner, pw->invoice,
+                                  post, acc, amount, exch, date, memo, num);
+        }
+        else
+        {
+            // New implementation: Allow the user to have a
+            // pre-selected transaction
+            Transaction *txn = pw->pre_existing_txn;
+            GncOwner *owner = &pw->owner;
 
+            Split *xfer_split = xaccTransFindSplitByAccount(txn, acc);
+
+            if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
+            {
+                g_message("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction.");
+                xfer_split = NULL;
+            }
+
+            if (!xfer_split)
+            {
+                g_message("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one.");
+
+                xaccTransBeginEdit (txn);
+                xaccTransDestroy (txn);
+                xaccTransCommitEdit (txn);
+
+                pw->pre_existing_txn = NULL;
+                gncOwnerApplyPayment (owner, pw->invoice,
+                                      post, acc, amount, exch, date, memo, num);
+            }
+            else
+            {
+                int i = 0;
+                xaccTransBeginEdit (txn);
+                while (i < xaccTransCountSplits(txn))
+                {
+                    Split *split = xaccTransGetSplit (txn, i);
+                    if (split == xfer_split)
+                    {
+                        ++i;
+                    }
+                    else
+                    {
+                        xaccSplitDestroy(split);
+                    }
+                }
+
+                // We have opened the txn for editing, and we have deleted all the other splits.
+                gncOwnerAssignPaymentTxn (owner, txn,
+                                          post, pw->invoice);
+
+                xaccTransCommitEdit (txn);
+            }
+        }
+
     }
     gnc_resume_gui_refresh ();
 
@@ -461,6 +566,9 @@
         if (owner->owner.undefined)
             gnc_payment_set_owner (pw, owner);
 
+        // Reset the setting about the pre-existing TXN
+        pw->pre_existing_txn = NULL;
+
         gtk_window_present (GTK_WINDOW(pw->dialog));
         return(pw);
     }
@@ -621,3 +729,138 @@
     return gnc_ui_payment_new_with_invoice (owner, book, NULL);
 }
 
+// ////////////////////////////////////////////////////////////
+
+static gboolean isAssetLiabType(GNCAccountType t)
+{
+    switch (t)
+    {
+    case ACCT_TYPE_RECEIVABLE:
+    case ACCT_TYPE_PAYABLE:
+        return FALSE;
+    default:
+        return (xaccAccountTypesCompatible(ACCT_TYPE_ASSET, t)
+                || xaccAccountTypesCompatible(ACCT_TYPE_LIABILITY, t));
+    }
+}
+static gboolean isAPARType(GNCAccountType t)
+{
+    switch (t)
+    {
+    case ACCT_TYPE_RECEIVABLE:
+    case ACCT_TYPE_PAYABLE:
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+static void increment_if_asset_account (gpointer data,
+                                        gpointer user_data)
+{
+    int *r = user_data;
+    const Split *split = data;
+    const Account *account = xaccSplitGetAccount(split);
+    if (isAssetLiabType(xaccAccountGetType(account)))
+        ++(*r);
+}
+static int countAssetAccounts(SplitList* slist)
+{
+    int result = 0;
+    g_list_foreach(slist, &increment_if_asset_account, &result);
+    return result;
+}
+
+static gint predicate_is_asset_account(gconstpointer a,
+                                       gconstpointer user_data)
+{
+    const Split *split = a;
+    const Account *account = xaccSplitGetAccount(split);
+    if (isAssetLiabType(xaccAccountGetType(account)))
+        return 0;
+    else
+        return -1;
+}
+static gint predicate_is_apar_account(gconstpointer a,
+                                      gconstpointer user_data)
+{
+    const Split *split = a;
+    const Account *account = xaccSplitGetAccount(split);
+    if (isAPARType(xaccAccountGetType(account)))
+        return 0;
+    else
+        return -1;
+}
+static Split *getFirstAssetAccountSplit(SplitList* slist)
+{
+    GList *r = g_list_find_custom(slist, NULL, &predicate_is_asset_account);
+    if (r)
+        return r->data;
+    else
+        return NULL;
+}
+static Split *getFirstAPARAccountSplit(SplitList* slist)
+{
+    GList *r = g_list_find_custom(slist, NULL, &predicate_is_apar_account);
+    if (r)
+        return r->data;
+    else
+        return NULL;
+}
+
+static gint predicate_not_equal(gconstpointer a,
+                                gconstpointer user_data)
+{
+    return (a != user_data);
+}
+static Split *getFirstOtherSplit(SplitList* slist, const Split *postaccount_split)
+{
+    GList *r = g_list_find_custom(slist, postaccount_split, &predicate_not_equal);
+    if (r)
+        return r->data;
+    else
+        return NULL;
+}
+
+// ///////////////
+
+PaymentWindow * gnc_ui_payment_new_with_txn (GncOwner *owner, Transaction *txn)
+{
+    SplitList *slist;
+
+    if (!txn)
+        return NULL;
+
+    // We require the txn to have one split in an A/R or A/P account.
+
+    slist = xaccTransGetSplitList(txn);
+    if (!slist)
+        return NULL;
+    if (countAssetAccounts(slist) == 0)
+    {
+        g_message("No asset splits in txn");
+        return NULL;
+    }
+
+    {
+        Split *xferaccount_split = getFirstAssetAccountSplit(slist);
+        Split *postaccount_split = getFirstAPARAccountSplit(slist);
+        gnc_numeric amount = xaccSplitGetValue(xferaccount_split);
+
+        PaymentWindow *pw = gnc_ui_payment_new(owner,
+                                               qof_instance_get_book(QOF_INSTANCE(txn)));
+
+        // Fill in the values from the given txn
+        pw->pre_existing_txn = txn;
+        gnc_ui_payment_window_set_num(pw, xaccTransGetNum(txn));
+        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, gnc_numeric_abs(amount));
+        gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(xferaccount_split));
+        gnc_ui_payment_window_set_postaccount(pw, xaccSplitGetAccount(postaccount_split));
+
+        return pw;
+    }
+}

Modified: gnucash/trunk/src/business/business-gnome/dialog-payment.h
===================================================================
--- gnucash/trunk/src/business/business-gnome/dialog-payment.h	2011-10-07 12:21:41 UTC (rev 21381)
+++ gnucash/trunk/src/business/business-gnome/dialog-payment.h	2011-10-07 21:49:56 UTC (rev 21382)
@@ -34,8 +34,16 @@
 PaymentWindow * gnc_ui_payment_new_with_invoice (GncOwner *owner,
         QofBook *book,
         GncInvoice *invoice);
+PaymentWindow * gnc_ui_payment_new_with_txn (GncOwner *owner, Transaction *txn);
 
 /* Destroy a payment window */
 void gnc_ui_payment_window_destroy (PaymentWindow *pw);
 
+void gnc_ui_payment_window_set_num (PaymentWindow *pw, const char* num);
+void gnc_ui_payment_window_set_memo (PaymentWindow *pw, const char* memo);
+void gnc_ui_payment_window_set_date (PaymentWindow *pw, const GDate *date);
+void gnc_ui_payment_window_set_amount (PaymentWindow *pw, gnc_numeric amount);
+void gnc_ui_payment_window_set_postaccount (PaymentWindow *pw, const Account* account);
+void gnc_ui_payment_window_set_xferaccount (PaymentWindow *pw, const Account* account);
+
 #endif /* _DIALOG_PAYMENT_H */



More information about the gnucash-changes mailing list