gnucash master: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Sun Jan 29 21:00:59 EST 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/11935675 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5bbfb8ef (commit)
	 via  https://github.com/Gnucash/gnucash/commit/34ed91ea (commit)
	 via  https://github.com/Gnucash/gnucash/commit/894f8241 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2d3d0506 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8e6fb15d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/dd50c7af (commit)
	 via  https://github.com/Gnucash/gnucash/commit/34be3c8b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3a6d1ea6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e615a577 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/67ab9e90 (commit)
	from  https://github.com/Gnucash/gnucash/commit/8a02f168 (commit)



commit 119356752f9c5546f98b4771094707a14b5f18c6
Merge: 8a02f168b 5bbfb8efd
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Jan 30 09:56:13 2023 +0800

    Merge branch 'maint'


commit 5bbfb8efd49f171b0674e04046cd8689155452f5
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sun Jan 29 23:11:49 2023 +0100

    Add proper indent to scheme changes from previous commit
    
    Committed seperately to make it easier to look at the actual changes.
    This commit only adds a 2 space indent to one function body.

diff --git a/gnucash/report/report-utilities.scm b/gnucash/report/report-utilities.scm
index eaf42e5ee..9974e2d6d 100644
--- a/gnucash/report/report-utilities.scm
+++ b/gnucash/report/report-utilities.scm
@@ -995,49 +995,49 @@ query instead.")
 ;;                 amount does not match the transaction amount
 ;; overpayment: a number indicating overpayment amount
 (define (gnc:payment-txn->payment-info txn)
-(let* ((apar-split (xaccTransGetFirstAPARAcctSplit txn #t))
-       (apar-acct (xaccSplitGetAccount apar-split)))
-  (let lp ((splits (xaccTransGetSplitList txn))
-           (invoices '())
-           (overpayment 0)
-           (opposing-splits '()))
-    (match splits
-      (() (vector invoices opposing-splits overpayment))
-      (((? not-APAR? split) . rest)
-       (gnc:msg "next " (gnc:strify split) " overpayment " (+ overpayment (xaccSplitConvertAmount split apar-acct)))
-       (lp rest invoices (+ overpayment (xaccSplitConvertAmount split apar-acct))
-           opposing-splits))
-      ((split . rest)
-       (let* ((lot (xaccSplitGetLot split))
-              (lot-all-splits (gnc-lot-get-split-list lot)))
-         (define split=? (cut equal? <> split))
-         (match (gncInvoiceGetInvoiceFromLot lot)
-           (() (let lp1 ((lot-splits lot-all-splits)
-                         (overpayment overpayment)
-                         (opposing-splits opposing-splits))
-                 (match lot-splits
-                   (() (lp rest invoices overpayment opposing-splits))
-                   (((? split=?) . tail) (lp1 tail overpayment opposing-splits))
-                   ((s . tail)
-                    (let* ((lot-bal (gnc-lot-get-balance lot))
-                           (lot-bal (if (sign-equal? lot-bal (xaccSplitConvertAmount s apar-acct))
-                                        0 lot-bal))
-                           (derived? (not (zero? lot-bal)))
-                           (partial-amount
-                            (fold
-                             (lambda (a b)
-                               (if (equal? s a) b (+ b (xaccSplitConvertAmount a apar-acct))))
-                             (- lot-bal) lot-all-splits)))
-                      (gnc:msg "next " (gnc:strify s) " overpayment " (+ overpayment partial-amount))
-                      (lp1 tail (+ overpayment partial-amount)
-                           (cons (list s partial-amount derived?)
-                                 opposing-splits)))))))
-           (inv
-            (gnc:msg "next " (gnc:strify split) " overpayment " (+ overpayment (xaccSplitConvertAmount split apar-acct)))
-            (lp rest
-                (cons (cons inv split) invoices)
-                (+ overpayment (xaccSplitConvertAmount split apar-acct))
-                opposing-splits)))))))))
+  (let* ((apar-split (xaccTransGetFirstAPARAcctSplit txn #t))
+        (apar-acct (xaccSplitGetAccount apar-split)))
+    (let lp ((splits (xaccTransGetSplitList txn))
+            (invoices '())
+            (overpayment 0)
+            (opposing-splits '()))
+      (match splits
+        (() (vector invoices opposing-splits overpayment))
+        (((? not-APAR? split) . rest)
+        (gnc:msg "next " (gnc:strify split) " overpayment " (+ overpayment (xaccSplitConvertAmount split apar-acct)))
+        (lp rest invoices (+ overpayment (xaccSplitConvertAmount split apar-acct))
+            opposing-splits))
+        ((split . rest)
+        (let* ((lot (xaccSplitGetLot split))
+                (lot-all-splits (gnc-lot-get-split-list lot)))
+          (define split=? (cut equal? <> split))
+          (match (gncInvoiceGetInvoiceFromLot lot)
+            (() (let lp1 ((lot-splits lot-all-splits)
+                          (overpayment overpayment)
+                          (opposing-splits opposing-splits))
+                  (match lot-splits
+                    (() (lp rest invoices overpayment opposing-splits))
+                    (((? split=?) . tail) (lp1 tail overpayment opposing-splits))
+                    ((s . tail)
+                      (let* ((lot-bal (gnc-lot-get-balance lot))
+                            (lot-bal (if (sign-equal? lot-bal (xaccSplitConvertAmount s apar-acct))
+                                          0 lot-bal))
+                            (derived? (not (zero? lot-bal)))
+                            (partial-amount
+                              (fold
+                              (lambda (a b)
+                                (if (equal? s a) b (+ b (xaccSplitConvertAmount a apar-acct))))
+                              (- lot-bal) lot-all-splits)))
+                        (gnc:msg "next " (gnc:strify s) " overpayment " (+ overpayment partial-amount))
+                        (lp1 tail (+ overpayment partial-amount)
+                            (cons (list s partial-amount derived?)
+                                  opposing-splits)))))))
+            (inv
+              (gnc:msg "next " (gnc:strify split) " overpayment " (+ overpayment (xaccSplitConvertAmount split apar-acct)))
+              (lp rest
+                  (cons (cons inv split) invoices)
+                  (+ overpayment (xaccSplitConvertAmount split apar-acct))
+                  opposing-splits)))))))))
 
 ;; create a stepped list, then add a date in the infinite future for
 ;; the "current" bucket

commit 34ed91eac969a3fb5cff8802a38293abeedc6ba6
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sun Jan 29 22:50:44 2023 +0100

    Bug 798734 - Aging Reports don't handle mixed currency payments and invoices without Trading Accounts
    
    Revisit the fix. It still made assumptions about the way
    payment transactions were created. It can now handle
    payment transaction either in the payment account
    currency or in the post account currency.

diff --git a/gnucash/report/report-utilities.scm b/gnucash/report/report-utilities.scm
index 79d3131f8..eaf42e5ee 100644
--- a/gnucash/report/report-utilities.scm
+++ b/gnucash/report/report-utilities.scm
@@ -987,7 +987,7 @@ query instead.")
 (define (not-APAR? s)
   (not (xaccAccountIsAPARType (xaccAccountGetType (xaccSplitGetAccount s)))))
 ;; analyse a payment transaction and return a 3-element vector:
-;; (vector invoices opposing-splits overpayment)
+;; (vector invoices overpayment opposing-splits)
 ;;
 ;; invoices: a list of (cons invoice inv-APAR-split)
 ;; opposing-splits: a list of (list pmt-APAR-split partial-amount derived?)
@@ -995,6 +995,8 @@ query instead.")
 ;;                 amount does not match the transaction amount
 ;; overpayment: a number indicating overpayment amount
 (define (gnc:payment-txn->payment-info txn)
+(let* ((apar-split (xaccTransGetFirstAPARAcctSplit txn #t))
+       (apar-acct (xaccSplitGetAccount apar-split)))
   (let lp ((splits (xaccTransGetSplitList txn))
            (invoices '())
            (overpayment 0)
@@ -1002,7 +1004,8 @@ query instead.")
     (match splits
       (() (vector invoices opposing-splits overpayment))
       (((? not-APAR? split) . rest)
-       (lp rest invoices (+ overpayment (xaccSplitGetValue split))
+       (gnc:msg "next " (gnc:strify split) " overpayment " (+ overpayment (xaccSplitConvertAmount split apar-acct)))
+       (lp rest invoices (+ overpayment (xaccSplitConvertAmount split apar-acct))
            opposing-splits))
       ((split . rest)
        (let* ((lot (xaccSplitGetLot split))
@@ -1017,22 +1020,24 @@ query instead.")
                    (((? split=?) . tail) (lp1 tail overpayment opposing-splits))
                    ((s . tail)
                     (let* ((lot-bal (gnc-lot-get-balance lot))
-                           (lot-bal (if (sign-equal? lot-bal (xaccSplitGetValue s))
+                           (lot-bal (if (sign-equal? lot-bal (xaccSplitConvertAmount s apar-acct))
                                         0 lot-bal))
                            (derived? (not (zero? lot-bal)))
                            (partial-amount
                             (fold
                              (lambda (a b)
-                               (if (equal? s a) b (+ b (xaccSplitGetValue a))))
+                               (if (equal? s a) b (+ b (xaccSplitConvertAmount a apar-acct))))
                              (- lot-bal) lot-all-splits)))
+                      (gnc:msg "next " (gnc:strify s) " overpayment " (+ overpayment partial-amount))
                       (lp1 tail (+ overpayment partial-amount)
                            (cons (list s partial-amount derived?)
                                  opposing-splits)))))))
            (inv
+            (gnc:msg "next " (gnc:strify split) " overpayment " (+ overpayment (xaccSplitConvertAmount split apar-acct)))
             (lp rest
                 (cons (cons inv split) invoices)
-                (+ overpayment (xaccSplitGetValue split))
-                opposing-splits))))))))
+                (+ overpayment (xaccSplitConvertAmount split apar-acct))
+                opposing-splits)))))))))
 
 ;; create a stepped list, then add a date in the infinite future for
 ;; the "current" bucket
@@ -1046,7 +1051,7 @@ query instead.")
 (define-public (gnc:owner-splits->aging-list splits num-buckets
                                              to-date date-type receivable?)
   (gnc:msg "processing " (qof-print-date to-date) " date-type " date-type
-           "receivable? " receivable?)
+           " receivable? " receivable?)
   (let ((bucket-dates (make-extended-interval-list to-date (- num-buckets 3)))
         (buckets (make-vector num-buckets 0)))
     (define (addbucket! idx amt)
@@ -1064,10 +1069,11 @@ query instead.")
                          (xaccSplitGetParent (car splits))))
                (lot (gncInvoiceGetPostedLot invoice))
                (lot-splits (gnc-lot-get-split-list lot))
+               (apar-acct (gncInvoiceGetPostedAcc invoice))
                (bal (fold
                      (lambda (a b)
                        (if (<= (xaccTransGetDate (xaccSplitGetParent a)) to-date)
-                           (+ (xaccSplitGetValue a) b)
+                           (+ (xaccSplitConvertAmount a apar-acct) b)
                            b))
                      0 lot-splits))
                (bal (if receivable? bal (- bal)))

commit 894f8241e127ce180eb74ee280a49c4a95ba88cf
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sun Jan 29 22:48:50 2023 +0100

    Revisit invoice payment in multi-currency context
    
    - Show proper amount in dialog when applying or editing an existing transaction as payment
    - Be more careful not to waste the existing payment split
    - If the user changed the payment amount while starting from an existing transaction
      unreconcile the changed payment split
    - Avoid needlessly changing transaction currency (only do so if the user chose
      a new transfer account and the old currency is neither the new transfer account's
      currency nor the post account's currency)

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index 75712bc58..fa9a403ac 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -1825,7 +1825,8 @@ PaymentWindow * gnc_ui_payment_new_with_txn (GtkWindow* parent, GncOwner *owner,
         GDate txn_date = xaccTransGetDatePostedGDate (txn);
         gnc_ui_payment_window_set_date(pw, &txn_date);
     }
-    gnc_ui_payment_window_set_amount(pw, xaccSplitGetValue(payment_split));
+
+    gnc_ui_payment_window_set_amount(pw, xaccSplitConvertAmount (payment_split, post_acct));
     if (payment_split)
         gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(payment_split));
     return pw;
diff --git a/libgnucash/engine/gncOwner.c b/libgnucash/engine/gncOwner.c
index c3c8b7315..5fcc0b24f 100644
--- a/libgnucash/engine/gncOwner.c
+++ b/libgnucash/engine/gncOwner.c
@@ -756,10 +756,12 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
     QofBook *book;
     Split *split;
     const char *name;
-    gnc_commodity *commodity;
+    gnc_commodity *post_comm, *xfer_comm;
     Split *xfer_split = NULL;
     Transaction *txn = NULL;
     GNCLot *payment_lot;
+    gnc_numeric xfer_amount = gnc_numeric_zero();
+    gnc_numeric txn_value = gnc_numeric_zero();
 
     /* Verify our arguments */
     if (!owner || !posted_acc || !xfer_acc) return NULL;
@@ -768,7 +770,9 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
     /* Compute the ancillary data */
     book = gnc_account_get_book (posted_acc);
     name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
-    commodity = gncOwnerGetCurrency (owner);
+    post_comm = xaccAccountGetCommodity (posted_acc);
+    xfer_comm = xaccAccountGetCommodity (xfer_acc);
+
 //    reverse = use_reversed_payment_amounts(owner);
 
     if (preset_txn && *preset_txn)
@@ -776,110 +780,90 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
 
     if (txn)
     {
-        xaccTransSetDescription (txn, name ? name : "");
+        int i = 0;
 
         /* Pre-existing transaction was specified. We completely clear it,
-         * except for the split in the transfer account, unless the
-         * transaction can't be reused (wrong currency, wrong transfer account).
-         * In that case, the transaction is simply removed and an new
-         * one created. */
-
+         * except for a pre-existing transfer split. We're very conservative
+         * in preserving that one as it may have been reconciled already. */
         xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);
-
-        if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
-        {
-            PINFO("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)
-        {
-            PINFO("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one.");
-
-            xaccTransBeginEdit (txn);
-            xaccTransDestroy (txn);
-            xaccTransCommitEdit (txn);
-
-            txn = NULL;
-        }
-        else
+        xaccTransBeginEdit (txn);
+        while (i < xaccTransCountSplits(txn))
         {
-            int i = 0;
-            xaccTransBeginEdit (txn);
-            while (i < xaccTransCountSplits(txn))
-            {
-                Split *split = xaccTransGetSplit (txn, i);
-                if (split == xfer_split)
-                {
-                    gnc_set_num_action (NULL, split, num, _("Payment"));
-                    ++i;
-                }
-                else
-                {
-                    xaccSplitDestroy(split);
-                }
-            }
-            /* Note: don't commit transaction now - that would insert an imbalance split.*/
+            Split *split = xaccTransGetSplit (txn, i);
+            if (split == xfer_split)
+                ++i;
+            else
+                xaccSplitDestroy(split);
         }
+        /* Note: don't commit transaction now - that would insert an imbalance split.*/
     }
-
-    /* Create the transaction if we don't have one yet */
-    if (!txn)
+    else
     {
         txn = xaccMallocTransaction (book);
         xaccTransBeginEdit (txn);
     }
 
+    /* Complete transaction setup */
+    xaccTransSetDescription (txn, name ? name : "");
+    if (!gnc_commodity_equal(xaccTransGetCurrency (txn), post_comm) &&
+        !gnc_commodity_equal (xaccTransGetCurrency (txn), xfer_comm))
+        xaccTransSetCurrency (txn, xfer_comm);
+
+    /* With all commodities involved known, define split amounts and txn value.
+     * - post amount (amount passed in as parameter) is always in post_acct commodity,
+     * - xfer amount requires conversion if the xfer account has a different
+     *   commodity than the post account.
+     * - txn value requires conversion if the post account has a different
+     *   commodity than the transaction */
+    if (gnc_commodity_equal(post_comm, xfer_comm))
+        xfer_amount = amount;
+    else
+        xfer_amount = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
+                                       GNC_HOW_RND_ROUND_HALF_UP);
+
+    if (gnc_commodity_equal(post_comm, xaccTransGetCurrency (txn)))
+        txn_value = amount;
+    else
+        txn_value = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
+                                      GNC_HOW_RND_ROUND_HALF_UP);
+
     /* Insert a split for the transfer account if we don't have one yet */
     if (!xfer_split)
     {
-
-        /* Set up the transaction */
-        xaccTransSetDescription (txn, name ? name : "");
-        /* set per book option */
-        xaccTransSetCurrency (txn, commodity);
-
-
         /* The split for the transfer account */
-        split = xaccMallocSplit (book);
-        xaccSplitSetMemo (split, memo);
+        xfer_split = xaccMallocSplit (book);
+        xaccSplitSetMemo (xfer_split, memo);
         /* set per book option */
-        gnc_set_num_action (NULL, split, num, _("Payment"));
+        gnc_set_num_action (NULL, xfer_split, num, _("Payment"));
         xaccAccountBeginEdit (xfer_acc);
-        xaccAccountInsertSplit (xfer_acc, split);
+        xaccAccountInsertSplit (xfer_acc, xfer_split);
         xaccAccountCommitEdit (xfer_acc);
-        xaccTransAppendSplit (txn, split);
+        xaccTransAppendSplit (txn, xfer_split);
 
-        if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
-        {
-            xaccSplitSetBaseValue (split, amount, commodity);
-        }
-        else
-        {
-            /* This will be a multi-currency transaction. The amount passed to this
-             * function is in the owner commodity (also used by the post account).
-             * For the xfer split we also need to value the payment in the xfer account's
-             * commodity.
-             * exch is from post account to xfer account so that can be used directly
-             * to calculate the equivalent amount in the xfer account's commodity. */
-            gnc_numeric xfer_amount = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
-                                                 GNC_HOW_RND_ROUND_HALF_UP);
-
-            xaccSplitSetAmount(split, xfer_amount); /* Payment in xfer account currency */
-            xaccSplitSetValue(split, amount); /* Payment in transaction currency */
-        }
+        xaccSplitSetAmount(xfer_split, xfer_amount); /* Payment in xfer account currency */
+        xaccSplitSetValue(xfer_split, txn_value); /* Payment in transaction currency */
+    }
+    /* For a pre-existing xfer split, let's check if the amount and value
+     * have changed. If so, update them and unreconcile. */
+    else if (!gnc_numeric_equal (xaccSplitGetAmount (xfer_split), xfer_amount) ||
+             !gnc_numeric_equal (xaccSplitGetValue (xfer_split), txn_value))
+    {
+        xaccSplitSetAmount (xfer_split, xfer_amount);
+        xaccSplitSetValue (xfer_split, txn_value);
+        xaccSplitSetReconcile (xfer_split, NREC);
     }
 
     /* Add a split in the post account */
     split = xaccMallocSplit (book);
     xaccSplitSetMemo (split, memo);
     /* set per book option */
-    gnc_set_num_action (NULL, split, num, _("Payment"));
+    xaccSplitSetAction (split, _("Payment"));
     xaccAccountBeginEdit (posted_acc);
     xaccAccountInsertSplit (posted_acc, split);
     xaccAccountCommitEdit (posted_acc);
     xaccTransAppendSplit (txn, split);
-    xaccSplitSetBaseValue (split, gnc_numeric_neg (amount), commodity);
+    xaccSplitSetAmount (split, gnc_numeric_neg (amount));
+    xaccSplitSetValue (split, gnc_numeric_neg (txn_value));
 
     /* Create a new lot for the payment */
     payment_lot = gnc_lot_new (book);
@@ -887,7 +871,7 @@ gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
     gnc_lot_add_split (payment_lot, split);
 
     /* Mark the transaction as a payment */
-    gnc_set_num_action (txn, NULL, num, _("Payment"));
+    xaccTransSetNum (txn, num);
     xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);
 
     /* Set date for transaction */

commit 2d3d05068d5a0d8f1349324616e37dc6fbc7f551
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sun Jan 29 11:37:54 2023 +0100

    Edit/assign payment - be more prudent not to lose data
    
    We can't handle the case where a transaction has splits in more than one
    APAR account. Instead of only warning that some of them will be lost
    refuse to continue and leave it to the user to fix the transaction first.

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index 4718942f4..75712bc58 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -1694,10 +1694,11 @@ static Split *select_payment_split (GtkWindow *parent, Transaction *txn)
 
 static GList *select_txn_lots (GtkWindow *parent, Transaction *txn, Account **post_acct, gboolean *abort)
 {
-    gboolean has_no_lot_apar_splits = FALSE;
-    SplitList *post_splits = NULL, *no_lot_post_splits = NULL;
+    SplitList *apar_splits = NULL; /* all spits in txn that are APAR type */
+    SplitList *apar_splits_no_lot = NULL; /* all splits in txn that are APAR type, but not tied to a lot */
     SplitList *iter;
     GList *txn_lots = NULL;
+    GList *unique_apar_accts = NULL;
 
     /* There's no use in continuing if I can't set the post_acct or abort variables */
     if (!post_acct || !abort)
@@ -1706,11 +1707,20 @@ static GList *select_txn_lots (GtkWindow *parent, Transaction *txn, Account **po
     *abort = FALSE;
     *post_acct = NULL;
 
-    post_splits = xaccTransGetAPARAcctSplitList (txn, FALSE);
-    for (iter = post_splits; iter; iter = iter->next)
+    /* Start by filtering out all APAR splits that have lots. Those are the ones we can
+       display as invoices and pre-payments in the payment window. */
+    apar_splits = xaccTransGetAPARAcctSplitList (txn, FALSE);
+    for (iter = apar_splits; iter; iter = iter->next)
     {
         GNCLot *postlot = NULL;
         Split *post_split = iter->data;
+        Account *apar_acct = xaccSplitGetAccount (post_split);
+
+        /* Store found apar_acct in our list of unique_apar_accts
+         * for later processing */
+        if (!g_list_find (unique_apar_accts, apar_acct))
+            unique_apar_accts = g_list_prepend (unique_apar_accts, apar_acct);
+
         postlot = xaccSplitGetLot (post_split);
         if (postlot)
         {
@@ -1718,59 +1728,55 @@ static GList *select_txn_lots (GtkWindow *parent, Transaction *txn, Account **po
             lot_info->lot = postlot;
             lot_info->amount = xaccSplitGetValue (post_split);
             txn_lots = g_list_prepend (txn_lots, lot_info);
-            *post_acct = xaccSplitGetAccount (post_split);
+            *post_acct = apar_acct;
         }
         else
-        {
-            /* Make sure not to override post_acct if it was set above from a lot split */
-            if (!*post_acct)
-                *post_acct = xaccSplitGetAccount (post_split);
-            no_lot_post_splits = g_list_prepend (no_lot_post_splits, post_split);
-            has_no_lot_apar_splits = TRUE;
-        }
+            apar_splits_no_lot = g_list_prepend (apar_splits_no_lot, post_split);
     }
+    g_list_free (apar_splits);
 
-    g_list_free (post_splits);
+    /* If no post_acct was selected from the postlots, fall back to the first apar split's
+     * account if there is one. */
+    if (!*post_acct && apar_splits_no_lot)
+        *post_acct = xaccSplitGetAccount (apar_splits_no_lot->data);
+    g_list_free (apar_splits_no_lot);
 
-    /* If the txn has both APAR splits linked to a business lot and
-     * splits that are not, issue a warning some will be discarded.
+    /* Abort if the txn has splits in more than one APAR account
+     * GnuCash can only handle one post account per payment transaction.
      */
-    if (has_no_lot_apar_splits && gnc_list_length_cmp (txn_lots, 0))
+    if (g_list_length (unique_apar_accts) > 1)
     {
         GtkWidget *dialog;
         char *split_str = g_strdup ("");
-        for (iter = no_lot_post_splits; iter; iter = iter->next)
+
+        for (iter = unique_apar_accts; iter; iter = iter->next)
         {
-            Split *post_split = iter->data;
-            char *tmp_str = gen_split_desc (txn, post_split);
-            char *tmp_str2 = g_strconcat(split_str, "• ", tmp_str, "\n", NULL);
-            g_free (tmp_str);
+            Account *acct = iter->data;
+            char *acct_name = gnc_account_get_full_name (acct);
+            char *tmp_str = g_strconcat(split_str, "• ", acct_name, "\n", NULL);
+            g_free (acct_name);
             g_free (split_str);
-            split_str = tmp_str2;
+            split_str = tmp_str;
         }
 
         dialog = gtk_message_dialog_new (parent,
                                          GTK_DIALOG_DESTROY_WITH_PARENT,
-                                         GTK_MESSAGE_WARNING,
-                                         GTK_BUTTONS_CANCEL,
-                                         _("The transaction has at least one split in a business account that is not part of a business transaction.\n"
-                                         "If you continue these splits will be ignored:\n\n%s\n"
-                                         "Do you wish to continue and ignore these splits?"),
+                                         GTK_MESSAGE_INFO,
+                                         GTK_BUTTONS_CLOSE,
+                                         _("This transaction has splits in multiple business accounts:\n\n%s\n"
+                                         "GnuCash can only handle transactions that post to a single account.\n\n"
+                                         "Please correct this manually by editing the transaction directly and then try again."),
                                          split_str);
-        gtk_dialog_add_buttons (GTK_DIALOG(dialog),
-                                _("Continue"), GTK_BUTTONS_OK, NULL);
-        gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_BUTTONS_CANCEL);
-        if (gtk_dialog_run (GTK_DIALOG(dialog)) != GTK_BUTTONS_OK)
-        {
-            *abort = TRUE;
-            g_list_free_full (txn_lots, g_free);
-            txn_lots = NULL;
-        }
+        gtk_dialog_run (GTK_DIALOG(dialog));
         gtk_widget_destroy (dialog);
+        PINFO("Multiple asset accounts in splits of txn \"%s\"; cannot use this for assigning a payment.",
+              xaccTransGetDescription(txn));
         g_free (split_str);
-    }
 
-    g_list_free (no_lot_post_splits);
+        *abort = TRUE;
+        g_list_free_full (txn_lots, g_free);
+        txn_lots = NULL;
+    }
 
     return txn_lots;
 }

commit 8e6fb15d44a497b11962772fb6ce3d064ca8a8b7
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sun Jan 29 11:32:58 2023 +0100

    Improve a few messages related to business payments

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index 54f382706..4718942f4 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -1573,18 +1573,29 @@ static char *gen_split_desc (Transaction *txn, Split *split)
     char *acct_name = gnc_account_get_full_name (xfer_acct);
     const char *action = gnc_get_action_num (txn, split);
     const char *memo = xaccSplitGetMemo (split);
+    char rec_state = xaccSplitGetReconcile (split);
     const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (xfer_acct, TRUE));
     char *split_str = NULL;
+    char *rec_str = NULL;
+
+    if (rec_state == CREC)
+        rec_str = g_strdup_printf("[%s] ", _("Cleared"));
+    else if (rec_state == YREC)
+        rec_str = g_strdup_printf("[%s] ", _("Reconciled"));
+    else
+        rec_str = g_strdup("");
 
     if (action && *action && memo && *memo)
-        split_str = g_strdup_printf ("%s: %s (%s, %s)", acct_name, print_amt,
+        split_str = g_strdup_printf ("%s%s: %s (%s, %s)", rec_str, acct_name, print_amt,
                                         action, memo);
     else if((action && *action) || (memo && *memo))
-        split_str = g_strdup_printf ("%s: %s (%s)", acct_name, print_amt,
+        split_str = g_strdup_printf ("%s%s: %s (%s)", rec_str, acct_name, print_amt,
                                         action ? action : memo);
     else
-        split_str = g_strdup_printf ("%s: %s", acct_name, print_amt);
+        split_str = g_strdup_printf ("%s%s: %s", rec_str, acct_name, print_amt);
+
     g_free (acct_name);
+    g_free (rec_str);
 
     return split_str;
 }
@@ -1621,8 +1632,8 @@ static Split *select_payment_split (GtkWindow *parent, Transaction *txn)
         GList *node;
         GtkWidget *first_rb = NULL;
         int answer = GTK_BUTTONS_OK;
-        const char *message = _("While this transaction has multiple splits that can be considered\nas 'the payment split', gnucash only knows how to handle one.\n"
-                                "Please select one, the others will be ignored.\n\n");
+        const char *message = _("While this transaction has multiple splits that can be considered\nas 'the payment split', GnuCash only knows how to handle one.\n"
+                                "Please select one, the others will be discarded.\n\n");
         GtkDialog *dialog = GTK_DIALOG(
                             gtk_dialog_new_with_buttons (_("Warning"),
                                                          parent,

commit dd50c7af13ed3954492e997884fa962b76df6328
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sun Jan 29 11:31:24 2023 +0100

    Multi-currency - show split amount rather than transaction value
    
    This issue was found while evaluating bug 798734, but not
    the immediate topic of that bug.

diff --git a/gnucash/gnome/dialog-payment.c b/gnucash/gnome/dialog-payment.c
index 3447debb1..54f382706 100644
--- a/gnucash/gnome/dialog-payment.c
+++ b/gnucash/gnome/dialog-payment.c
@@ -1568,7 +1568,7 @@ gboolean gnc_ui_payment_is_customer_payment(const Transaction *txn)
 // ///////////////
 static char *gen_split_desc (Transaction *txn, Split *split)
 {
-    gnc_numeric value = xaccSplitGetValue(split);
+    gnc_numeric value = xaccSplitGetAmount(split);
     Account *xfer_acct = xaccSplitGetAccount(split);
     char *acct_name = gnc_account_get_full_name (xfer_acct);
     const char *action = gnc_get_action_num (txn, split);

commit 34be3c8b14c97fd06a2a113d2a960f2089e3a279
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun Jan 29 14:25:41 2023 +0800

    [report-utilities] use fold for gnc:accounts-count-splits
    
    previous definition would build intermediate lists for each step. also
    handles the null account-list.

diff --git a/gnucash/report/report-utilities.scm b/gnucash/report/report-utilities.scm
index 36253fe31..79d3131f8 100644
--- a/gnucash/report/report-utilities.scm
+++ b/gnucash/report/report-utilities.scm
@@ -741,7 +741,7 @@ query instead.")
 
 ;; function to count the total number of splits to be iterated
 (define (gnc:accounts-count-splits accounts)
-  (apply + (map length (map xaccAccountGetSplitList accounts))))
+  (fold (lambda (a b) (+ b (length (xaccAccountGetSplitList a)))) 0 accounts))
 
 ;; Sums up any splits of a certain type affecting a set of accounts.
 ;; the type is an alist '((str "match me") (cased #f) (regexp #f))
diff --git a/gnucash/report/test/test-report-utilities.scm b/gnucash/report/test/test-report-utilities.scm
index 1016e3999..c198ec430 100644
--- a/gnucash/report/test/test-report-utilities.scm
+++ b/gnucash/report/test/test-report-utilities.scm
@@ -477,6 +477,10 @@
         44
         (gnc:accounts-count-splits (list expense income)))
 
+      (test-equal "gnc:accounts-count-splits null"
+        0
+        (gnc:accounts-count-splits '()))
+
       (let ((account-balances (gnc:get-assoc-account-balances
                                (list bank gbp-bank)
                                (lambda (acct)

commit 3a6d1ea6631a3c3ac90eedbad59c8c0ec89ed645
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sun Jan 29 10:14:38 2023 +0100

    Bug 798737 - Minor grammatical error - 'for' missing in 'You will be asked a conversion rate for each.'

diff --git a/gnucash/gnome/dialog-invoice.c b/gnucash/gnome/dialog-invoice.c
index 8307cec9f..c02e64fcd 100644
--- a/gnucash/gnome/dialog-invoice.c
+++ b/gnucash/gnome/dialog-invoice.c
@@ -999,7 +999,7 @@ gnc_invoice_post(InvoiceWindow *iw, struct post_invoice_params *post_params)
     gncInvoiceSetCurrency (invoice, gncOwnerGetCurrency (gncInvoiceGetOwner (invoice)));
 
     /* Fill in the conversion prices with feedback from the user */
-    text = _("One or more of the entries are for accounts different from the invoice/bill currency. You will be asked a conversion rate for each.");
+    text = _("One or more of the entries are for accounts different from the invoice/bill currency. You will be asked to enter a conversion rate for each.");
 
     /* Ask the user for conversion rates for all foreign currencies
      * (relative to the invoice currency) */

commit e615a5775aebc78e105e33c3dd9ef7b3a43c220e
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat Jan 28 20:53:24 2023 +0800

    Bug 798734 - Aging Reports don't handle mixed currency payments and invoices without Trading Accounts

diff --git a/gnucash/report/report-utilities.scm b/gnucash/report/report-utilities.scm
index 1d2901158..36253fe31 100644
--- a/gnucash/report/report-utilities.scm
+++ b/gnucash/report/report-utilities.scm
@@ -1002,7 +1002,7 @@ query instead.")
     (match splits
       (() (vector invoices opposing-splits overpayment))
       (((? not-APAR? split) . rest)
-       (lp rest invoices (+ overpayment (xaccSplitGetAmount split))
+       (lp rest invoices (+ overpayment (xaccSplitGetValue split))
            opposing-splits))
       ((split . rest)
        (let* ((lot (xaccSplitGetLot split))
@@ -1017,13 +1017,13 @@ query instead.")
                    (((? split=?) . tail) (lp1 tail overpayment opposing-splits))
                    ((s . tail)
                     (let* ((lot-bal (gnc-lot-get-balance lot))
-                           (lot-bal (if (sign-equal? lot-bal (xaccSplitGetAmount s))
+                           (lot-bal (if (sign-equal? lot-bal (xaccSplitGetValue s))
                                         0 lot-bal))
                            (derived? (not (zero? lot-bal)))
                            (partial-amount
                             (fold
                              (lambda (a b)
-                               (if (equal? s a) b (+ b (xaccSplitGetAmount a))))
+                               (if (equal? s a) b (+ b (xaccSplitGetValue a))))
                              (- lot-bal) lot-all-splits)))
                       (lp1 tail (+ overpayment partial-amount)
                            (cons (list s partial-amount derived?)
@@ -1031,7 +1031,7 @@ query instead.")
            (inv
             (lp rest
                 (cons (cons inv split) invoices)
-                (+ overpayment (xaccSplitGetAmount split))
+                (+ overpayment (xaccSplitGetValue split))
                 opposing-splits))))))))
 
 ;; create a stepped list, then add a date in the infinite future for
@@ -1067,7 +1067,7 @@ query instead.")
                (bal (fold
                      (lambda (a b)
                        (if (<= (xaccTransGetDate (xaccSplitGetParent a)) to-date)
-                           (+ (xaccSplitGetAmount a) b)
+                           (+ (xaccSplitGetValue a) b)
                            b))
                      0 lot-splits))
                (bal (if receivable? bal (- bal)))

commit 67ab9e90d264979d46a3426100160fbcbcf5ae1f
Author: luzpaz <luzpaz at users.noreply.github.com>
Date:   Wed Jan 25 15:07:39 2023 +0000

    Fix some typos

diff --git a/bindings/python/example_scripts/rest-api/gnucash_rest.py b/bindings/python/example_scripts/rest-api/gnucash_rest.py
index e17e77d6c..f28c0e831 100644
--- a/bindings/python/example_scripts/rest-api/gnucash_rest.py
+++ b/bindings/python/example_scripts/rest-api/gnucash_rest.py
@@ -1826,7 +1826,7 @@ def gnc_numeric_from_decimal(decimal_value):
     TEN = int(Decimal(0).radix()) # this is always 10
     numerator_place_value = 1
     # add each digit to the final value multiplied by the place value
-    # from least significant to most sigificant
+    # from least significant to most significant
     for i in range(len(digits)-1,-1,-1):
         numerator += digits[i] * numerator_place_value
         numerator_place_value *= TEN
diff --git a/bindings/python/example_scripts/simple_invoice_insert.py b/bindings/python/example_scripts/simple_invoice_insert.py
index 391b05c6d..89c9c93d7 100644
--- a/bindings/python/example_scripts/simple_invoice_insert.py
+++ b/bindings/python/example_scripts/simple_invoice_insert.py
@@ -66,7 +66,7 @@ def gnc_numeric_from_decimal(decimal_value):
     TEN = int(Decimal(0).radix()) # this is always 10
     numerator_place_value = 1
     # add each digit to the final value multiplied by the place value
-    # from least significant to most sigificant
+    # from least significant to most significant
     for i in range(len(digits)-1,-1,-1):
         numerator += digits[i] * numerator_place_value
         numerator_place_value *= TEN
diff --git a/doc/examples/customers_import.csv b/doc/examples/customers_import.csv
index 599aadc6e..6e9ae4bac 100644
--- a/doc/examples/customers_import.csv
+++ b/doc/examples/customers_import.csv
@@ -8,7 +8,7 @@ id,company,name,addr1,addr2,addr3,addr4,phone,fax,email,notes,shipname,shipaddr1
 #company with the same ID will be UPDATED.  This may not be what you want!
 000099,Average Company,Accounts Dept,50 Poor Avenue,,,,,,,,,,,,,,,
 ,Academy,Academy,Some Street,,,,555-237-6959,,,,,,,,,,shipmail
-,company,name,addr1,addr2,addr3,addr4,phone,fax,emai,lnotes,shipname,shipaddr1,shipaddr2,shipaddr3,shipaddr4,shipphone,shipfax,shipemail
+,company,name,addr1,addr2,addr3,addr4,phone,fax,email,notes,shipname,shipaddr1,shipaddr2,shipaddr3,shipaddr4,shipphone,shipfax,shipemail
 ,No Address Company,Accounts,,,,,,,,,,,,,,,,
 
 #Just another example after a blank line
diff --git a/libgnucash/app-utils/calculation/fin.c b/libgnucash/app-utils/calculation/fin.c
index 3c04118fb..bc011b20e 100644
--- a/libgnucash/app-utils/calculation/fin.c
+++ b/libgnucash/app-utils/calculation/fin.c
@@ -103,7 +103,7 @@
  * interest only loan), or large enough  to fully repay both the interest  and
  * principal during the term of the loan (a fully amoritized loan). Many loans
  * fall somewhere between, with payments that do not fully cover repayment  of
- * both the principal and interst. These loans require a larger final  payment
+ * both the principal and interest. These loans require a larger final payment
  * (balloon)  to  complete  their  amortization.  Payments  may  occur  at the
  * beginning or end of a payment period. If you and your friend had agreed  on
  * monthly repayment of  the $800 loan  at 12% NAR  compounded monthly, twelve
@@ -220,7 +220,7 @@
  *   compounding Frequency, CF, is simply the number of times per
  *   year, the monies in the financial transaction are compounded. In
  *   the U.S., monies are usually compounded daily on bank deposits,
- *   and monthly on loans. Somtimes Long term deposits are compounded
+ *   and monthly on loans. Sometimes Long term deposits are compounded
  *   quarterly or weekly.
  *
  *   The Payment Frequency, PF, is simply how often during a year
@@ -596,7 +596,7 @@
  *       T[n] = -i*n*(PV + C) - i*C*n(n+1)/2
  *       T[n] = -i*n*(PV + (C*(n - 1)/2))
  *
- * Note: substituing for C = -PV/N, in the equations for PV[n], I[n],
+ * Note: substituting for C = -PV/N, in the equations for PV[n], I[n],
  *   P[n], and T[n] would give the following equations:
  *
  *       PV[n] = PV*(1 - n/N)
@@ -739,12 +739,12 @@
  *   1. The payment *, interest paid, principal paid and remaining PV
  *   for each payment period are computed and displayed. At the end of
  *   each year a summary is computed and displayed and the total
- *   interest paid is diplayed at the end.
+ *   interest paid is displayed at the end.
  *
  *   2. A summary is computed and displayed for each year. The
  *   interest paid during the year is computed and displayed as well
  *   as the remaining balance at years end.  The total interest paid
- *   is diplayed at the end.
+ *   is displayed at the end.
  *
  *   3. An amortization schedule is computed for a common method of
  *   advanced payment of principal is computed and displayed. In this
@@ -1016,7 +1016,7 @@
  * Example 6: Balloon Payment
  * On long term loans, small changes in the periodic payments can generate
  * large changes in the future value. If the monthly payment in example 5 is
- * rounded down to $1125, how much addtional (balloon) payment will be due
+ * rounded down to $1125, how much additional (balloon) payment will be due
  * with the final regular payment.
  * <>pmt=-1125
  * -1,125
@@ -2034,7 +2034,7 @@ Amortization_Schedule (amort_sched_ptr amortsched)
                 else
                 {
                     /* remaining pv less than advanced principal payment reduce
-                     * advanced pricipal payment to remaining pv and set
+                     * advanced principal payment to remaining pv and set
                      * remaining pv to fv */
                     adv_pmt = -pv;
                     pv = fv;
@@ -2137,7 +2137,7 @@ Amortization_Schedule (amort_sched_ptr amortsched)
     case 'o':
         /* Constant payment to principal use constant payment equal to
          * original pv divided by number of periods.  constant payment to
-         * pricipal could be amount specified by user.  */
+         * principal could be amount specified by user.  */
         amortsched->schedule.first_yr =
             amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
         amortsched->total_periods = n;
diff --git a/libgnucash/app-utils/options.scm b/libgnucash/app-utils/options.scm
index dc49f45ae..8491933f3 100644
--- a/libgnucash/app-utils/options.scm
+++ b/libgnucash/app-utils/options.scm
@@ -455,7 +455,7 @@ the option '~a'."))
       #f #f #f #f)))
 
 ;; budget option
-;; TODO: need to double-check this proc (dates back to r11545 or eariler)
+;; TODO: need to double-check this proc (dates back to r11545 or earlier)
 ;;
 ;; Always takes/returns a budget
 ;; Stores the GUID in the KVP
diff --git a/libgnucash/doc/constraints.txt b/libgnucash/doc/constraints.txt
index 672325977..9d3a92840 100644
--- a/libgnucash/doc/constraints.txt
+++ b/libgnucash/doc/constraints.txt
@@ -71,7 +71,7 @@ returned.
 
 Simple/ad-hoc lazy evaluation works well when data dependencies are 
 simple, but it breaks down when there are too many/circular
-relationships.  It becomes all too easy to get trapped in inifinite
+relationships.  It becomes all too easy to get trapped in infinite
 loops of corrections.   The goal of moving to a formal constraint
 system is to introduce specific, well-defined sync points where 
 constraint checking can be done, without incuring circular
diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp
index 12b7dcbfe..16b964b7e 100644
--- a/libgnucash/engine/qofinstance.cpp
+++ b/libgnucash/engine/qofinstance.cpp
@@ -176,7 +176,7 @@ static void qof_instance_class_init(QofInstanceClass *klass)
                            "Object Last Update",
                            "A pointer to the last time this object was "
                            "updated.  This value is present for use by "
-                           "backends and shouldnot be written by other "
+                           "backends and shouldn't be written by other "
                            "code.",
                            G_PARAM_READWRITE));
 



Summary of changes:
 .../example_scripts/rest-api/gnucash_rest.py       |   2 +-
 .../example_scripts/simple_invoice_insert.py       |   2 +-
 doc/examples/customers_import.csv                  |   2 +-
 gnucash/gnome/dialog-invoice.c                     |   2 +-
 gnucash/gnome/dialog-payment.c                     | 108 +++++++++-------
 gnucash/report/report-utilities.scm                |  90 ++++++-------
 gnucash/report/test/test-report-utilities.scm      |   4 +
 libgnucash/app-utils/calculation/fin.c             |  16 +--
 libgnucash/doc/constraints.txt                     |   2 +-
 libgnucash/engine/gncOwner.c                       | 140 +++++++++------------
 libgnucash/engine/qofinstance.cpp                  |   2 +-
 11 files changed, 191 insertions(+), 179 deletions(-)



More information about the gnucash-changes mailing list