From fd12d3900c56cd2c789737e53be312e6cb9ca221 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Wed, 15 Jun 2022 19:43:20 +0800 Subject: [PATCH] [Transaction.c] use heuristics to determine txn->txn_type --- bindings/python/tests/test_transaction.py | 9 ---- libgnucash/engine/Transaction.c | 45 +++++++++++++++----- libgnucash/engine/Transaction.h | 14 ++++-- libgnucash/engine/TransactionP.h | 2 + libgnucash/engine/test/utest-Transaction.cpp | 7 +-- 5 files changed, 48 insertions(+), 29 deletions(-) diff --git a/bindings/python/tests/test_transaction.py b/bindings/python/tests/test_transaction.py index 446a7b8e41..44f042ffd2 100644 --- a/bindings/python/tests/test_transaction.py +++ b/bindings/python/tests/test_transaction.py @@ -112,15 +112,6 @@ class TestTransaction(TransactionSession): self.trans.ClearReadOnly() self.assertEqual( None, self.trans.GetReadOnly() ) - def test_txntype(self): - self.assertEqual( '\x00', self.trans.GetTxnType() ) - TYPE = 'I' - self.trans.SetTxnType(TYPE) - self.assertEqual( TYPE, self.trans.GetTxnType() ) - TYPE = 'P' - self.trans.SetTxnType(TYPE) - self.assertEqual( TYPE, self.trans.GetTxnType() ) - def test_num(self): NUM = '5' self.assertEqual( '', self.trans.GetNum() ) diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c index c4c933209b..ce4761b6b6 100644 --- a/libgnucash/engine/Transaction.c +++ b/libgnucash/engine/Transaction.c @@ -279,6 +279,7 @@ gnc_transaction_init(Transaction* trans) trans->notes = (char*) is_unset; trans->doclink = (char*) is_unset; trans->void_reason = (char*) is_unset; + trans->txn_type = TXN_TYPE_UNCACHED; LEAVE (" "); } @@ -1705,6 +1706,7 @@ xaccTransCommitEdit (Transaction *trans) qof_instance_set_dirty(QOF_INSTANCE(trans)); } + trans->txn_type = TXN_TYPE_UNCACHED; qof_commit_edit_part2(QOF_INSTANCE(trans), (void (*) (QofInstance *, QofBackendError)) trans_on_error, @@ -2551,22 +2553,43 @@ xaccTransRetDateDue(const Transaction *trans) } char -xaccTransGetTxnType (const Transaction *trans) +xaccTransGetTxnType (Transaction *trans) { - const char *s = NULL; - GValue v = G_VALUE_INIT; - char ret = TXN_TYPE_NONE; + gboolean has_nonAPAR_amount = FALSE; if (!trans) return TXN_TYPE_NONE; - qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP); - if (G_VALUE_HOLDS_STRING (&v)) + + if (trans->txn_type != TXN_TYPE_UNCACHED) + return trans->txn_type; + + trans->txn_type = TXN_TYPE_NONE; + for (GList *n = xaccTransGetSplitList (trans); n; n = g_list_next (n)) { - s = g_value_get_string (&v); - if (s && strlen (s) == 1) - ret = s[0]; + Account *acc = xaccSplitGetAccount (n->data); + + if (!acc) + continue; + + if (!xaccAccountIsAPARType (xaccAccountGetType (acc)) && + !gnc_numeric_zero_p (xaccSplitGetValue (n->data))) + has_nonAPAR_amount = TRUE; + else if (trans->txn_type == TXN_TYPE_NONE) + { + GNCLot *lot = xaccSplitGetLot (n->data); + GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot); + GncOwner owner; + + if (invoice && trans == gncInvoiceGetPostedTxn (invoice)) + trans->txn_type = TXN_TYPE_INVOICE; + else if (invoice || gncOwnerGetOwnerFromLot (lot, &owner)) + trans->txn_type = TXN_TYPE_PAYMENT; + } } - g_value_unset (&v); - return ret; + + if (!has_nonAPAR_amount && (trans->txn_type == TXN_TYPE_PAYMENT)) + trans->txn_type = TXN_TYPE_LINK; + + return trans->txn_type; } const char * diff --git a/libgnucash/engine/Transaction.h b/libgnucash/engine/Transaction.h index 0389960b2f..1ecd58ffd3 100644 --- a/libgnucash/engine/Transaction.h +++ b/libgnucash/engine/Transaction.h @@ -121,6 +121,7 @@ GType gnc_transaction_get_type(void); /** @name Transaction Type field values @{ */ +#define TXN_TYPE_UNCACHED '?' /** Transaction type not yet cached */ #define TXN_TYPE_NONE '\0' /**< No transaction type */ #define TXN_TYPE_INVOICE 'I' /**< Transaction is an invoice */ #define TXN_TYPE_PAYMENT 'P' /**< Transaction is a payment */ @@ -302,14 +303,21 @@ gboolean xaccTransUseTradingAccounts(const Transaction *trans); */ void xaccTransSortSplits (Transaction *trans); -/** Set the Transaction Type +/** Set the Transaction Type: note the type will be saved into the + * Transaction kvp property as a backward compatibility measure, for + * previous GnuCash versions whose xaccTransGetTxnType reads from the + * kvp slots. * * See #TXN_TYPE_NONE, #TXN_TYPE_INVOICE and #TXN_TYPE_PAYMENT */ void xaccTransSetTxnType (Transaction *trans, char type); -/** Returns the Transaction Type + +/** Returns the Transaction Type: note this type will be derived from + * the transaction splits, returning #TXN_TYPE_NONE, + * #TXN_TYPE_INVOICE, #TXN_TYPE_LINK, or #TXN_TYPE_PAYMENT according + * to heuristics. It does not query the transaction kvp slots. * * See #TXN_TYPE_NONE, #TXN_TYPE_INVOICE and #TXN_TYPE_PAYMENT */ -char xaccTransGetTxnType (const Transaction *trans); +char xaccTransGetTxnType (Transaction *trans); /** Sets the transaction Number (or ID) field; rather than use this function * directly, see 'gnc_set_num_action' in engine/engine-helpers.c & .h which diff --git a/libgnucash/engine/TransactionP.h b/libgnucash/engine/TransactionP.h index d7b141d0cf..3e107ff390 100644 --- a/libgnucash/engine/TransactionP.h +++ b/libgnucash/engine/TransactionP.h @@ -122,6 +122,8 @@ struct transaction_s char * void_reason; char * notes; + char txn_type; + /* Cached bool value to indicate whether this is a closing txn. This is * cached from the KVP value because it is queried a lot. Tri-state value: -1 * = uninitialized; 0 = FALSE, 1 = TRUE. */ diff --git a/libgnucash/engine/test/utest-Transaction.cpp b/libgnucash/engine/test/utest-Transaction.cpp index 54069d15e7..c9bbf0f0c1 100644 --- a/libgnucash/engine/test/utest-Transaction.cpp +++ b/libgnucash/engine/test/utest-Transaction.cpp @@ -1838,13 +1838,8 @@ test_xaccTransGetReadOnly (Fixture *fixture, gconstpointer pData) static void test_xaccTransGetTxnType (Fixture *fixture, gconstpointer pData) { - const char i = 'I'; - const char p = 'P'; auto txn = fixture->txn; - xaccTransSetTxnType(txn, i); - g_assert_cmpint (i, ==, xaccTransGetTxnType(txn)); - xaccTransSetTxnType(txn, p); - g_assert_cmpint (p, ==, xaccTransGetTxnType(txn)); + g_assert_cmpint (TXN_TYPE_NONE, ==, xaccTransGetTxnType(txn)); } /* xaccTransGetReadOnly C: 7 in 5 Local: 1:0:0