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