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