mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
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. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@17710 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
1de131ed1b
commit
294176f40d
@ -1282,7 +1282,7 @@ gnc_lot_sort_func (GNCLot *a, GNCLot *b)
|
||||
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 @@ gncOwnerApplyPayment (GncOwner *owner, GncInvoice* invoice,
|
||||
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 @@ gncOwnerApplyPayment (GncOwner *owner, GncInvoice* invoice,
|
||||
xaccTransSetDatePostedTS (txn, &date);
|
||||
xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);
|
||||
|
||||
|
||||
/* The split for the transfer account */
|
||||
split = xaccMallocSplit (book);
|
||||
xaccSplitSetMemo (split, memo);
|
||||
@ -1326,8 +1328,20 @@ gncOwnerApplyPayment (GncOwner *owner, GncInvoice* invoice,
|
||||
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
|
||||
@ -1397,20 +1411,20 @@ gncOwnerApplyPayment (GncOwner *owner, GncInvoice* invoice,
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ gncOwnerApplyPayment (GncOwner *owner, GncInvoice* invoice,
|
||||
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 @@ gncOwnerApplyPayment (GncOwner *owner, GncInvoice* invoice,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ gncInvoiceUnpost (GncInvoice *invoice, gboolean reset_tax_tables);
|
||||
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);
|
||||
|
||||
|
||||
|
@ -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_invoice_set_owner (GtkWidget *widget, GncOwner *owner)
|
||||
|
||||
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 @@ gnc_fill_account_select_combo (GtkWidget *combo, GNCBook *book,
|
||||
== -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 @@ GList *
|
||||
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)));
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ GList * gnc_business_commodities (GncOwner *owner);
|
||||
|
||||
/* 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
|
||||
|
@ -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 @@ struct _payment_window {
|
||||
GncOwner owner;
|
||||
GncInvoice * invoice;
|
||||
GList * acct_types;
|
||||
GList * acct_commodities;
|
||||
};
|
||||
|
||||
|
||||
@ -78,7 +81,7 @@ gnc_payment_window_refresh_handler (GHashTable *changes, gpointer data)
|
||||
{
|
||||
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 @@ gnc_payment_dialog_invoice_changed(PaymentWindow *pw)
|
||||
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,15 +132,36 @@ gnc_payment_dialog_owner_changed(PaymentWindow *pw)
|
||||
|
||||
/* 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) {
|
||||
@ -271,15 +295,41 @@ gnc_payment_ok_cb (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
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_payment_window_destroy_cb (GtkWidget *widget, gpointer data)
|
||||
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 @@ new_payment_window (GncOwner *owner, GNCBook *book, GncInvoice *invoice)
|
||||
/* 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 @@ new_payment_window (GncOwner *owner, GNCBook *book, GncInvoice *invoice)
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user