r17710 - gnucash/trunk/src/business - Add support for mixed currency for invoice payment
Christian Stimming
cstim at cvs.gnucash.org
Thu Nov 20 12:00:53 EST 2008
Author: cstim
Date: 2008-11-20 12:00:53 -0500 (Thu, 20 Nov 2008)
New Revision: 17710
Trac: http://svn.gnucash.org/trac/changeset/17710
Modified:
gnucash/trunk/src/business/business-core/gncInvoice.c
gnucash/trunk/src/business/business-core/gncInvoice.h
gnucash/trunk/src/business/business-gnome/business-gnome-utils.c
gnucash/trunk/src/business/business-gnome/business-gnome-utils.h
gnucash/trunk/src/business/business-gnome/dialog-payment.c
Log:
Add support for mixed currency for invoice payment
This patch extends the payment dialog to allow paying foreign-currency
AP with local currency, or local-currency AP with foreign currency (I
don't know if there's a use-case for the latter, but it would have been
harder to code to NOT support it).
Patch by Jamie Campbell.
Modified: gnucash/trunk/src/business/business-core/gncInvoice.c
===================================================================
--- gnucash/trunk/src/business/business-core/gncInvoice.c 2008-11-20 17:00:45 UTC (rev 17709)
+++ gnucash/trunk/src/business/business-core/gncInvoice.c 2008-11-20 17:00:53 UTC (rev 17710)
@@ -1282,7 +1282,7 @@
Transaction *
gncOwnerApplyPayment (GncOwner *owner, GncInvoice* invoice,
Account *posted_acc, Account *xfer_acc,
- gnc_numeric amount, Timespec date,
+ gnc_numeric amount, gnc_numeric exch, Timespec date,
const char *memo, const char *num)
{
QofBook *book;
@@ -1296,6 +1296,7 @@
gnc_commodity *commodity;
gnc_numeric split_amt;
gboolean reverse, inv_passed = TRUE;
+ gnc_numeric payment_value=amount;
/* Verify our arguments */
if (!owner || !posted_acc || !xfer_acc) return NULL;
@@ -1318,6 +1319,7 @@
xaccTransSetDatePostedTS (txn, &date);
xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);
+
/* The split for the transfer account */
split = xaccMallocSplit (book);
xaccSplitSetMemo (split, memo);
@@ -1326,9 +1328,21 @@
xaccAccountInsertSplit (xfer_acc, split);
xaccAccountCommitEdit (xfer_acc);
xaccTransAppendSplit (txn, split);
- xaccSplitSetBaseValue (split, reverse ? amount :
- gnc_numeric_neg (amount), commodity);
+ if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
+ {
+ xaccSplitSetBaseValue (split, reverse ? amount :
+ gnc_numeric_neg (amount), commodity);
+ }
+ else
+ {
+ /* Need to value the payment in terms of the owner commodity */
+ xaccSplitSetAmount(split, reverse ? amount : gnc_numeric_neg (amount));
+ payment_value = gnc_numeric_mul(amount, exch, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
+ xaccSplitSetValue(split, reverse ? payment_value : gnc_numeric_neg(payment_value));
+ }
+
+
/* Now, find all "open" lots in the posting account for this
* company and apply the payment on a FIFO basis. Create
* a new split for each open lot until the payment is gone.
@@ -1397,20 +1411,20 @@
}
/*
- * If the amount <= the balance; we're done -- apply the amount.
- * Otherwise, apply the balance, subtract that from the amount,
+ * If the payment_value <= the balance; we're done -- apply the payment_value.
+ * Otherwise, apply the balance, subtract that from the payment_value,
* and move on to the next one.
*/
- if (gnc_numeric_compare (amount, balance) <= 0) {
- /* amount <= balance */
- split_amt = amount;
+ if (gnc_numeric_compare (payment_value, balance) <= 0) {
+ /* payment_value <= balance */
+ split_amt = payment_value;
} else {
- /* amount > balance */
+ /* payment_value > balance */
split_amt = balance;
}
- /* reduce the amount by split_amt */
- amount = gnc_numeric_sub (amount, split_amt, GNC_DENOM_AUTO, GNC_DENOM_LCD);
+ /* reduce the payment_value by split_amt */
+ payment_value = gnc_numeric_sub (payment_value, split_amt, GNC_DENOM_AUTO, GNC_DENOM_LCD);
/* Create the split for this lot in the post account */
split = xaccMallocSplit (book);
@@ -1427,14 +1441,14 @@
if (this_invoice)
qof_event_gen (&this_invoice->inst, QOF_EVENT_MODIFY, NULL);
- if (gnc_numeric_zero_p (amount))
+ if (gnc_numeric_zero_p (payment_value))
break;
}
g_list_free (fifo);
/* If there is still money left here, then create a pre-payment lot */
- if (gnc_numeric_positive_p (amount)) {
+ if (gnc_numeric_positive_p (payment_value)) {
if (prepay_lot == NULL) {
prepay_lot = gnc_lot_new (book);
gncOwnerAttachToLot (owner, prepay_lot);
@@ -1445,8 +1459,8 @@
xaccSplitSetAction (split, _("Pre-Payment"));
xaccAccountInsertSplit (posted_acc, split);
xaccTransAppendSplit (txn, split);
- xaccSplitSetBaseValue (split, reverse ? gnc_numeric_neg (amount) :
- amount, commodity);
+ xaccSplitSetBaseValue (split, reverse ? gnc_numeric_neg (payment_value) :
+ payment_value, commodity);
gnc_lot_add_split (prepay_lot, split);
}
Modified: gnucash/trunk/src/business/business-core/gncInvoice.h
===================================================================
--- gnucash/trunk/src/business/business-core/gncInvoice.h 2008-11-20 17:00:45 UTC (rev 17709)
+++ gnucash/trunk/src/business/business-core/gncInvoice.h 2008-11-20 17:00:53 UTC (rev 17710)
@@ -160,7 +160,7 @@
Transaction *
gncOwnerApplyPayment (GncOwner *owner, GncInvoice *invoice,
Account *posted_acc, Account *xfer_acc,
- gnc_numeric amount, Timespec date,
+ gnc_numeric amount, gnc_numeric exch, Timespec date,
const char *memo, const char *num);
Modified: gnucash/trunk/src/business/business-gnome/business-gnome-utils.c
===================================================================
--- gnucash/trunk/src/business/business-gnome/business-gnome-utils.c 2008-11-20 17:00:45 UTC (rev 17709)
+++ gnucash/trunk/src/business/business-gnome/business-gnome-utils.c 2008-11-20 17:00:53 UTC (rev 17710)
@@ -49,6 +49,8 @@
#include "dialog-employee.h"
#include "dialog-invoice.h"
+#include "gnc-commodity.h"
+
typedef enum {
GNCSEARCH_TYPE_SELECT,
GNCSEARCH_TYPE_EDIT
@@ -303,7 +305,7 @@
void
gnc_fill_account_select_combo (GtkWidget *combo, GNCBook *book,
- GList *acct_types)
+ GList *acct_types, GList *acct_commodities)
{
GtkListStore *store;
GtkEntry *entry;
@@ -335,6 +337,17 @@
== -1)
continue;
+ /* Only present accounts with the right commodity, if that's a
+ restriction */
+ if (acct_commodities)
+ {
+ if ( g_list_find_custom( acct_commodities,
+ GINT_TO_POINTER(xaccAccountGetCommodity(account)),
+ gnc_commodity_compare) == NULL ) {
+ continue;
+ }
+ }
+
name = xaccAccountGetFullName (account);
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), name);
g_free(name);
@@ -370,6 +383,7 @@
gnc_business_commodities (GncOwner *owner)
{
g_return_val_if_fail (owner, NULL);
+ g_return_val_if_fail (gncOwnerGetCurrency(owner), NULL);
return (g_list_prepend (NULL, gncOwnerGetCurrency(owner)));
}
Modified: gnucash/trunk/src/business/business-gnome/business-gnome-utils.h
===================================================================
--- gnucash/trunk/src/business/business-gnome/business-gnome-utils.h 2008-11-20 17:00:45 UTC (rev 17709)
+++ gnucash/trunk/src/business/business-gnome/business-gnome-utils.h 2008-11-20 17:00:53 UTC (rev 17710)
@@ -67,7 +67,8 @@
/* Fill in a combo box with the appropriate list of accounts */
void gnc_fill_account_select_combo (GtkWidget *combo, GNCBook *book,
- GList *acct_types);
+ GList *acct_types,
+ GList *acct_commodities);
/* Create an optionmenu of available billing terms and attach it to
Modified: gnucash/trunk/src/business/business-gnome/dialog-payment.c
===================================================================
--- gnucash/trunk/src/business/business-gnome/dialog-payment.c 2008-11-20 17:00:45 UTC (rev 17709)
+++ gnucash/trunk/src/business/business-gnome/dialog-payment.c 2008-11-20 17:00:53 UTC (rev 17710)
@@ -45,6 +45,8 @@
#include "dialog-payment.h"
#include "business-gnome-utils.h"
+#include "dialog-transfer.h"
+
#define DIALOG_PAYMENT_CUSTOMER_CM_CLASS "customer-payment-dialog"
#define DIALOG_PAYMENT_VENDOR_CM_CLASS "vendor-payment-dialog"
@@ -65,6 +67,7 @@
GncOwner owner;
GncInvoice * invoice;
GList * acct_types;
+ GList * acct_commodities;
};
@@ -78,7 +81,7 @@
{
PaymentWindow *pw = data;
- gnc_fill_account_select_combo (pw->post_combo, pw->book, pw->acct_types);
+ gnc_fill_account_select_combo (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
}
static void
@@ -110,8 +113,8 @@
static void
gnc_payment_dialog_owner_changed(PaymentWindow *pw)
{
- Account *last_acct;
- GUID *guid;
+ Account *last_acct=NULL;
+ GUID *guid=NULL;
KvpValue* value;
KvpFrame* slots;
@@ -129,16 +132,37 @@
/* Now handle the account tree */
slots = gncOwnerGetSlots(&pw->owner);
- if (!slots) return;
+ if (slots)
+ {
+ value = kvp_frame_get_slot_path(slots, "payment", "last_acct", NULL);
+ if (value)
+ {
+ guid = kvp_value_get_guid(value);
+ }
+ }
- value = kvp_frame_get_slot_path(slots, "payment", "last_acct", NULL);
- if (!value) return;
-
- guid = kvp_value_get_guid(value);
- if (!guid) return;
+ /* refresh the post and acc available accounts, but cleanup first */
+ if (pw->acct_types)
+ {
+ g_list_free(pw->acct_types);
+ pw->acct_types = NULL;
+ }
- last_acct = xaccAccountLookup(guid, pw->book);
+ if (pw->acct_commodities)
+ {
+ g_list_free(pw->acct_commodities);
+ pw->acct_commodities = NULL;
+ }
+ pw->acct_types = gnc_business_account_types(&pw->owner);
+ pw->acct_commodities = gnc_business_commodities (&pw->owner);
+ gnc_fill_account_select_combo (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
+
+ if (guid)
+ {
+ last_acct = xaccAccountLookup(guid, pw->book);
+ }
+
/* Set the last-used transfer account */
if (last_acct) {
gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
@@ -271,15 +295,41 @@
{
const char *memo, *num;
Timespec date;
+ gnc_numeric exch = gnc_numeric_create(1,1); //default to "one to one" rate
/* Obtain all our ancillary information */
memo = gtk_entry_get_text (GTK_ENTRY (pw->memo_entry));
num = gtk_entry_get_text (GTK_ENTRY (pw->num_entry));
date = gnc_date_edit_get_date_ts (GNC_DATE_EDIT (pw->date_edit));
+ /* If the 'acc' account and the post account don't have the same
+ currency, we need to get the user to specify the exchange rate */
+ if (!gnc_commodity_equal(xaccAccountGetCommodity(acc), xaccAccountGetCommodity(post)))
+ {
+ XferDialog* xfer;
+
+ text = _("The transfer and post accounts are associated with different currencies. Please specify the conversion rate.");
+
+ xfer = gnc_xfer_dialog(pw->dialog, acc);
+ gnc_info_dialog(pw->dialog, "%s", text);
+
+ gnc_xfer_dialog_select_to_account(xfer,post);
+ gnc_xfer_dialog_set_amount(xfer, amount);
+
+ /* All we want is the exchange rate so prevent the user from thinking
+ it makes sense to mess with other stuff */
+ gnc_xfer_dialog_set_from_show_button_active(xfer, FALSE);
+ gnc_xfer_dialog_set_to_show_button_active(xfer, FALSE);
+ gnc_xfer_dialog_hide_from_account_tree(xfer);
+ gnc_xfer_dialog_hide_to_account_tree(xfer);
+ gnc_xfer_dialog_is_exchange_dialog(xfer, &exch);
+ gnc_xfer_dialog_run_until_done(xfer);
+ }
+
/* Now apply the payment */
gncOwnerApplyPayment (&pw->owner, pw->invoice,
- post, acc, amount, date, memo, num);
+ post, acc, amount, exch, date, memo, num);
+
}
gnc_resume_gui_refresh ();
@@ -306,6 +356,7 @@
gnc_unregister_gui_component (pw->component_id);
g_list_free (pw->acct_types);
+ g_list_free (pw->acct_commodities);
g_free (pw);
}
@@ -377,6 +428,8 @@
/* Compute the post-to account types */
pw->acct_types = gnc_business_account_types (owner);
+ pw->acct_commodities = gnc_business_commodities (owner);
+
/* Open and read the XML */
xml = gnc_glade_xml_new ("payment.glade", "Payment Dialog");
pw->dialog = glade_xml_get_widget (xml, "Payment Dialog");
@@ -444,8 +497,7 @@
QOF_EVENT_DESTROY);
/* Fill in the post_combo and account_tree widgets */
- gnc_fill_account_select_combo (pw->post_combo, pw->book, pw->acct_types);
-
+ gnc_fill_account_select_combo (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
/* Show it all */
gtk_widget_show_all (pw->dialog);
More information about the gnucash-changes
mailing list