r21478 - gnucash/trunk/src/engine - Rework owner payment code to work with credit notes as well as invoices

Geert Janssens gjanssens at code.gnucash.org
Sat Oct 22 12:38:23 EDT 2011


Author: gjanssens
Date: 2011-10-22 12:38:22 -0400 (Sat, 22 Oct 2011)
New Revision: 21478
Trac: http://svn.gnucash.org/trac/changeset/21478

Modified:
   gnucash/trunk/src/engine/gncOwner.c
Log:
Rework owner payment code to work with credit notes as well as invoices

Modified: gnucash/trunk/src/engine/gncOwner.c
===================================================================
--- gnucash/trunk/src/engine/gncOwner.c	2011-10-22 14:16:52 UTC (rev 21477)
+++ gnucash/trunk/src/engine/gncOwner.c	2011-10-22 16:38:22 UTC (rev 21478)
@@ -761,7 +761,7 @@
                          Account *posted_account, GncInvoice* invoice)
 {
     Account *inv_posted_acc;
-    GList *lot_list, *fifo;
+    GList *lot_iter, *open_lot_fifo;
     GNCLot *inv_posted_lot = NULL, *prepay_lot = NULL;
     gnc_numeric split_amt;
     gboolean inv_passed = TRUE;
@@ -771,7 +771,6 @@
     gint result = 0;
     gnc_numeric payment_value;
     const char *memo;
-    gboolean reverse = use_reversed_payment_amounts(owner);
 
     g_assert(owner);
     g_assert(txn);
@@ -794,9 +793,10 @@
         // Retrieve the payment value from the existing first split.
         Split *asset_split = xaccTransGetSplit(txn, 0);
         g_assert(asset_split);
-        payment_value = xaccSplitGetValue(asset_split);
-        if (!reverse)
-            payment_value = gnc_numeric_neg(payment_value);
+
+        /* Note: to balance the transaction the payment to assign
+         * must have the opposite sign of the existing first split */
+        payment_value = gnc_numeric_neg(xaccSplitGetValue(asset_split));
         memo = xaccSplitGetMemo(asset_split);
     }
 
@@ -805,16 +805,17 @@
      * a new split for each open lot until the payment is gone.
      */
 
-    fifo = xaccAccountFindOpenLots (posted_account, gnc_lot_match_invoice_owner,
-                                    (gpointer)owner,
-                                    (GCompareFunc)gnc_lot_sort_func);
+    open_lot_fifo = xaccAccountFindOpenLots (posted_account, gnc_lot_match_invoice_owner,
+                                             (gpointer)owner,
+                                             (GCompareFunc)gnc_lot_sort_func);
 
-    /* Check if an invoice was passed in, and if so, does it match the
-     * account, and is it an open lot?  If so, put it at the beginning
-     * of the lot list fifo so we post to this invoice's lot first.
-     */
+    /* Check if an invoice was passed in. */
     if (invoice)
     {
+        /* If so, does it match the account, and is it an open lot?
+         * If so, put it at the beginning of the lot list fifo so we
+         * post to this invoice's lot first.
+         */
         inv_posted_acc = gncInvoiceGetPostedAcc(invoice);
         inv_posted_lot = gncInvoiceGetPostedLot(invoice);
         if (inv_posted_acc && inv_posted_lot &&
@@ -823,7 +824,7 @@
                 !gnc_lot_is_closed(inv_posted_lot))
         {
             /* Put this invoice at the beginning of the FIFO */
-            fifo = g_list_prepend (fifo, inv_posted_lot);
+            open_lot_fifo = g_list_prepend (open_lot_fifo, inv_posted_lot);
             inv_passed = FALSE;
         }
     }
@@ -833,11 +834,11 @@
     /* Now iterate over the fifo until the payment is fully applied
      * (or all the lots are paid)
      */
-    for (lot_list = fifo; lot_list; lot_list = lot_list->next)
+    for (lot_iter = open_lot_fifo; lot_iter; lot_iter = lot_iter->next)
     {
         gnc_numeric balance;
 
-        GNCLot *lot = lot_list->data;
+        GNCLot *lot = lot_iter->data;
 
         /* Skip this lot if it matches the invoice that was passed in and
          * we've seen it already.  This way we post to it the first time
@@ -856,13 +857,12 @@
 
         balance = gnc_lot_get_balance (lot);
 
-        if (!reverse)
-            balance = gnc_numeric_neg (balance);
-
-        /* If the balance is "negative" then skip this lot.
-         * (just save the pre-payment lot for later)
+        /* The balance can be positive or negative. But in order to assign a payment to it,
+         * it has to have the opposite sign of the payment_value we have left.
+         * If they are of the same sign, we may reserve it as the pre-payment lot for later
          */
-        if (gnc_numeric_negative_p (balance))
+        if ( (gnc_numeric_negative_p (balance) && gnc_numeric_negative_p (payment_value)) ||
+             (gnc_numeric_positive_p (balance) && gnc_numeric_positive_p (payment_value)) )
         {
             if (prepay_lot)
             {
@@ -870,25 +870,32 @@
             }
             else
             {
-                prepay_lot = lot;
+                /* A lot can only be used as a pre-payment lot if it has no document (invoice/credit note) attached */
+                if (!gncInvoiceGetInvoiceFromLot(lot))
+                    prepay_lot = lot;
             }
             continue;
         }
 
         /*
-         * If the payment_value <= the balance; we're done -- apply the payment_value.
+         * If there is less to pay than there's open in the lot; we're done -- apply the payment_value.
+         * Note that payment_value and balance are opposite in sign, so we have to compare absolute values here
+         *
          * Otherwise, apply the balance, subtract that from the payment_value,
          * and move on to the next one.
          */
-        if (gnc_numeric_compare (payment_value, balance) <= 0)
+        if (gnc_numeric_compare (gnc_numeric_abs (payment_value), gnc_numeric_abs (balance)) <= 0)
         {
-            /* payment_value <= balance */
+            /* abs(payment_value) <= abs(balance) */
             split_amt = payment_value;
         }
         else
         {
-            /* payment_value > balance */
-            split_amt = balance;
+            /* abs(payment_value) > abs(balance)
+             * Remember payment_value and balance are opposite in sign,
+             * and we want a payment to neutralize the current balance
+             * so we need to negate here */
+            split_amt = gnc_numeric_neg (balance);
         }
 
         /* reduce the payment_value by split_amt */
@@ -901,11 +908,11 @@
         xaccSplitSetAction (split, _("Payment"));
         xaccAccountInsertSplit (posted_account, split);
         xaccTransAppendSplit (txn, split);
-        xaccSplitSetBaseValue (split, reverse ? gnc_numeric_neg (split_amt) :
-                               split_amt, txn_commodity);
+        xaccSplitSetBaseValue (split, split_amt, txn_commodity);
         gnc_lot_add_split (lot, split);
 
-        /* Now send an event for the invoice so it gets updated as paid */
+        /* If the lot was linked to a document (invoice/credit note),
+         * send an event for it so it gets updated as paid */
         {
             GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(lot);
             if (this_invoice)
@@ -916,10 +923,10 @@
             break;
     }
 
-    g_list_free (fifo);
+    g_list_free (open_lot_fifo);
 
     /* If there is still money left here, then create a pre-payment lot */
-    if (gnc_numeric_positive_p (payment_value))
+    if (!gnc_numeric_zero_p (payment_value))
     {
         if (prepay_lot == NULL)
         {
@@ -932,8 +939,7 @@
         xaccSplitSetAction (split, _("Pre-Payment"));
         xaccAccountInsertSplit (posted_account, split);
         xaccTransAppendSplit (txn, split);
-        xaccSplitSetBaseValue (split, reverse ? gnc_numeric_neg (payment_value) :
-                               payment_value, txn_commodity);
+        xaccSplitSetBaseValue (split, payment_value, txn_commodity);
         gnc_lot_add_split (prepay_lot, split);
     }
 



More information about the gnucash-changes mailing list