gnucash stable: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Sat Jan 27 01:26:28 EST 2024


Updated	 via  https://github.com/Gnucash/gnucash/commit/a3015443 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/49af9ff1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/97829185 (commit)
	from  https://github.com/Gnucash/gnucash/commit/b31baf34 (commit)



commit a3015443768473626e04c5cb68ec6a952c827067
Merge: b31baf344f 49af9ff16b
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat Jan 27 14:26:13 2024 +0800

    Merge branch 'stock-acct-metadata' into stable #1858


commit 49af9ff16bf23a628b4b0e0aa43b83cd14c0b00b
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Fri Jan 26 11:23:03 2024 +0800

    [assistant-stock-transaction] store & retrieve associated account as metadata

diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index f4efeea365..1b26ac18ab 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -88,6 +88,11 @@ void stock_assistant_cancel_cb  (GtkAssistant *gtkassistant, gpointer user_data)
 static const char* GNC_PREFS_GROUP = "dialogs.stock-assistant";
 static const char* ASSISTANT_STOCK_TRANSACTION_CM_CLASS = "assistant-stock-transaction";
 
+static const char* DIVIDEND_KVP_TAG = "stock-dividends";
+static const char* CAPGAINS_KVP_TAG = "stock-capgains";
+static const char* PROCEEDS_KVP_TAG = "stock-cash-proceeds";
+static const char* FEES_KVP_TAG = "stock-broker-fees";
+
 /** A mask-enumerator for defining what information will be collected for a split.
  */
 enum class FieldMask : unsigned
@@ -531,13 +536,16 @@ protected:
     const char* m_memo;
     const char* m_action;
     gnc_numeric m_balance = gnc_numeric_zero();
+    const char* m_kvp_tag;
 public:
     StockTransactionEntry() :
         m_enabled{false}, m_debit_side{false}, m_allow_zero{false},  m_account{nullptr},
-        m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{nullptr} {}
-    StockTransactionEntry(const char* action) :
+        m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{nullptr},
+        m_kvp_tag{nullptr} {}
+    StockTransactionEntry(const char* action, const char* kvp_tag) :
         m_enabled{false}, m_debit_side{false}, m_allow_zero{false},  m_account{nullptr},
-        m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{action} {}
+        m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{action},
+        m_kvp_tag{kvp_tag} {}
     StockTransactionEntry(const StockTransactionEntry&) = default;
     virtual ~StockTransactionEntry() = default;
     /** Set up the state variables from the FieldMask.
@@ -554,6 +562,7 @@ public:
     virtual Account* account() const { return m_account; }
     virtual const char* print_account() const;
     virtual void set_memo(const char* memo) { m_memo = memo; }
+    virtual const char* get_kvp_tag () { return m_kvp_tag; }
     virtual const char* memo() const { return m_memo; }
     virtual void set_value(gnc_numeric amount);
     virtual GncNumeric value() { return (gnc_numeric_check(m_value) ? GncNumeric{} : GncNumeric(m_value)); }
@@ -766,7 +775,7 @@ public:
         PINFO("Stock Entry");
     }
     StockTransactionStockEntry(const char* action) :
-        StockTransactionEntry{action}, m_amount{gnc_numeric_error(GNC_ERROR_ARG)}
+        StockTransactionEntry{action, nullptr}, m_amount{gnc_numeric_error(GNC_ERROR_ARG)}
     {
         PINFO("Stock Entry");
     }
@@ -983,7 +992,7 @@ class StockTransactionFeesEntry : public StockTransactionEntry
     bool m_capitalize;
 public:
     StockTransactionFeesEntry() : StockTransactionEntry{}, m_capitalize{false} {}
-    StockTransactionFeesEntry(const char* action) : StockTransactionEntry{action}, m_capitalize{false} {}
+    StockTransactionFeesEntry(const char* action, const char *tag) : StockTransactionEntry{action, tag}, m_capitalize{false} {}
     void set_fieldmask(FieldMask mask) override;
     void set_capitalize(bool capitalize) override { m_capitalize = capitalize; }
     bool do_capitalize() const override { return m_capitalize; }
@@ -1098,10 +1107,10 @@ public:
         m_acct{account},
         m_currency{gnc_account_get_currency_or_parent(account)},
         m_stock_entry{std::make_unique<StockTransactionStockEntry>(NC_ ("Stock Assistant: Page name","Stock"))},
-        m_cash_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Cash"))},
-        m_fees_entry{std::make_unique<StockTransactionFeesEntry>(NC_ ("Stock Assistant: Page name","Fees"))},
-        m_dividend_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Dividend"))},
-        m_capgains_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Capital Gains"))}
+        m_cash_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Cash"), PROCEEDS_KVP_TAG)},
+        m_fees_entry{std::make_unique<StockTransactionFeesEntry>(NC_ ("Stock Assistant: Page name","Fees"), FEES_KVP_TAG)},
+        m_dividend_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Dividend"), DIVIDEND_KVP_TAG)},
+        m_capgains_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Capital Gains"), CAPGAINS_KVP_TAG)}
     {
         DEBUG ("StockAssistantModel constructor\n");
         m_stock_entry->set_account(m_acct);
@@ -1417,7 +1426,12 @@ StockAssistantModel::create_transaction ()
     xaccTransSetDatePostedSecsNormalized (trans, m_transaction_date);
     AccountVec accounts;
     std::for_each (m_list_of_splits.begin(), m_list_of_splits.end(),
-                   [&](auto& entry){ entry->create_split (trans, accounts); });
+                   [&](auto& entry)
+                   {
+                       entry->create_split (trans, accounts);
+                       if (entry->get_kvp_tag() && entry->account())
+                           xaccAccountSetAssociatedAccount (m_acct, entry->get_kvp_tag(), entry->account());
+                   });
     add_price (book);
     xaccTransCommitEdit (trans);
     std::for_each (accounts.begin(), accounts.end(), xaccAccountCommitEdit);
@@ -1596,7 +1610,7 @@ class GncAccountSelector
     GtkWidget* m_selector;
 public:
     GncAccountSelector (GtkBuilder *builder, AccountTypeList types,
-                        gnc_commodity *currency);
+                        gnc_commodity *currency, Account *default_acct);
     void attach (GtkBuilder *builder, const char *table_id,
                  const char *label_ID, int row);
     void connect (StockTransactionEntry*);
@@ -1613,7 +1627,7 @@ gnc_account_sel_changed_cb (GtkWidget* widget, StockTransactionEntry* entry)
 }
 
 GncAccountSelector::GncAccountSelector (GtkBuilder *builder, AccountTypeList types,
-                                        gnc_commodity *currency) :
+                                        gnc_commodity *currency, Account *default_acct) :
     m_selector{gnc_account_sel_new ()}
 {
     auto accum = [](auto a, auto b) { return g_list_prepend(a, (gpointer)b); };
@@ -1624,6 +1638,8 @@ GncAccountSelector::GncAccountSelector (GtkBuilder *builder, AccountTypeList typ
     gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(m_selector), acct_list, curr_list);
     gnc_account_sel_set_default_new_commodity(GNC_ACCOUNT_SEL(m_selector), currency);
     gnc_account_sel_set_new_account_modal (GNC_ACCOUNT_SEL(m_selector), true);
+    if (default_acct)
+        gnc_account_sel_set_account (GNC_ACCOUNT_SEL(m_selector), default_acct, true);
     g_list_free(acct_list);
     g_list_free(curr_list);
 }
@@ -2006,7 +2022,8 @@ public:
 PageCash::PageCash(GtkBuilder *builder, Account* account)
     : m_page(get_widget(builder, "cash_details_page")),
       m_account(builder, {ACCT_TYPE_ASSET, ACCT_TYPE_BANK},
-                gnc_account_get_currency_or_parent(account)),
+                gnc_account_get_currency_or_parent(account),
+                xaccAccountGetAssociatedAccount (account, PROCEEDS_KVP_TAG)),
       m_memo(get_widget(builder, "cash_memo_entry")),
       m_value(builder, gnc_account_get_currency_or_parent(account))
 {
@@ -2068,7 +2085,8 @@ PageFees::PageFees(GtkBuilder *builder, Account* account)
     : m_page(get_widget(builder, "fees_details_page")),
       m_capitalize(
           get_widget(builder, "capitalize_fees_checkbutton")),
-      m_account(builder, {ACCT_TYPE_EXPENSE}, gnc_account_get_currency_or_parent(account)),
+      m_account(builder, {ACCT_TYPE_EXPENSE}, gnc_account_get_currency_or_parent(account),
+                xaccAccountGetAssociatedAccount (account, FEES_KVP_TAG)),
       m_memo(get_widget(builder, "fees_memo_entry")),
       m_value(builder, gnc_account_get_currency_or_parent(account)),
       m_stock_account(account)
@@ -2155,7 +2173,8 @@ public:
 
 PageDividend::PageDividend(GtkBuilder *builder, Account* account)
     : m_page(get_widget(builder, "dividend_details_page")),
-      m_account(builder, {ACCT_TYPE_INCOME}, gnc_account_get_currency_or_parent(account)),
+      m_account(builder, {ACCT_TYPE_INCOME}, gnc_account_get_currency_or_parent(account),
+                xaccAccountGetAssociatedAccount (account, DIVIDEND_KVP_TAG)),
       m_memo(get_widget(builder, "dividend_memo_entry")),
       m_value(builder, gnc_account_get_currency_or_parent(account))
 {
@@ -2204,7 +2223,8 @@ public:
 
 PageCapGain::PageCapGain (GtkBuilder *builder, Account* account) :
     m_page (get_widget (builder, "capgains_details_page")),
-    m_account (builder, { ACCT_TYPE_INCOME }, gnc_account_get_currency_or_parent(account)),
+    m_account (builder, { ACCT_TYPE_INCOME }, gnc_account_get_currency_or_parent(account),
+               xaccAccountGetAssociatedAccount (account, CAPGAINS_KVP_TAG)),
     m_memo (get_widget (builder, "capgains_memo_entry")),
     m_value (builder, gnc_account_get_currency_or_parent(account))
 {

commit 97829185863cc90d51d4034411dcdaa78f618e9f
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Fri Jan 26 00:12:37 2024 +0800

    [account.cpp] add more account metadata - assoc account
    
    the tag denotes the type of associated account eg. "dividend"
    "capgains" "cash" "fees"

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 1a53ff6026..378aff1a46 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -2579,6 +2579,34 @@ xaccAccountSetNotes (Account *acc, const char *str)
     set_kvp_string_tag (acc, "notes", str);
 }
 
+
+void
+xaccAccountSetAssociatedAccount (Account *acc, const char *tag, const Account* assoc_acct)
+{
+    g_return_if_fail (GNC_IS_ACCOUNT(acc));
+    g_return_if_fail (tag && *tag);
+
+    std::vector<std::string> path = { "associated-account", tag };
+    xaccAccountBeginEdit(acc);
+
+    PINFO ("setting %s assoc %s account = %s", xaccAccountGetName (acc), tag,
+           assoc_acct ? xaccAccountGetName (assoc_acct) : nullptr);
+
+    if (GNC_IS_ACCOUNT(assoc_acct))
+    {
+        GValue v = G_VALUE_INIT;
+        g_value_init (&v, GNC_TYPE_GUID);
+        g_value_set_static_boxed (&v, xaccAccountGetGUID (assoc_acct));
+        qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, path);
+        g_value_unset (&v);
+    }
+    else
+        qof_instance_set_path_kvp (QOF_INSTANCE (acc), nullptr, path);
+
+    mark_account (acc);
+    xaccAccountCommitEdit(acc);
+}
+
 void
 xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
 {
@@ -3367,6 +3395,28 @@ xaccAccountGetNotes (const Account *acc)
     return rv;
 }
 
+Account*
+xaccAccountGetAssociatedAccount (const Account *acc, const char *tag)
+{
+    g_return_val_if_fail (GNC_IS_ACCOUNT(acc), nullptr);
+    g_return_val_if_fail (tag && *tag, nullptr);
+
+    GValue v = G_VALUE_INIT;
+    qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v, { "associated-account", tag });
+
+    auto guid = static_cast<GncGUID*>(G_VALUE_HOLDS_BOXED (&v) ? g_value_get_boxed(&v) : nullptr);
+    g_value_unset (&v);
+
+    if (!guid)
+        return nullptr;
+
+    auto assoc_acct = xaccAccountLookup (guid, gnc_account_get_book (acc));
+    PINFO ("retuning %s assoc %s account = %s", xaccAccountGetName (acc), tag,
+           xaccAccountGetName (assoc_acct));
+    return assoc_acct;
+}
+
+
 gnc_commodity *
 DxaccAccountGetCurrency (const Account *acc)
 {
diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h
index f1db851cf4..daac6b52af 100644
--- a/libgnucash/engine/Account.h
+++ b/libgnucash/engine/Account.h
@@ -312,6 +312,11 @@ typedef enum
     void xaccAccountSetSortReversed (Account *account, gboolean sortreversed);
     /** Set the account's notes */
     void xaccAccountSetNotes (Account *account, const char *notes);
+
+    /** Set the account's associated account e.g. stock account -> dividend account */
+    void xaccAccountSetAssociatedAccount (Account *acc, const char *tag,
+                                          const Account *assoc_acct);
+
     /** Set the last num field of an Account */
     void xaccAccountSetLastNum (Account *account, const char *num);
     /** Set the account's lot order policy */
@@ -416,6 +421,9 @@ typedef enum
     gboolean xaccAccountGetSortReversed (const Account *account);
     /** Get the account's notes */
     const char * xaccAccountGetNotes (const Account *account);
+
+    /** Get the account's associated account e.g. stock account -> dividend account */
+    Account* xaccAccountGetAssociatedAccount (const Account *acc, const char *tag);
     /** Get the last num field of an Account */
     const char * xaccAccountGetLastNum (const Account *account);
     /** Get the account's lot order policy */
diff --git a/libgnucash/engine/test/utest-Account.cpp b/libgnucash/engine/test/utest-Account.cpp
index e09e5426b8..fbabc77f93 100644
--- a/libgnucash/engine/test/utest-Account.cpp
+++ b/libgnucash/engine/test/utest-Account.cpp
@@ -1237,6 +1237,25 @@ test_gnc_account_kvp_setters_getters (Fixture *fixture, gconstpointer pData)
     xaccAccountSetNotes (account, nullptr);
     g_assert_cmpstr (xaccAccountGetNotes (account), ==, nullptr);
 
+    // Associated Account getter/setter
+    g_assert_null (xaccAccountGetAssociatedAccount (account, "test"));
+
+    g_test_expect_message ("gnc.engine", G_LOG_LEVEL_CRITICAL,
+                           "*xaccAccountSetAssociatedAccount*assertion*tag && *tag*");
+    xaccAccountSetAssociatedAccount (account, nullptr, account);
+    g_test_assert_expected_messages();
+
+    g_test_expect_message ("gnc.engine", G_LOG_LEVEL_CRITICAL,
+                           "*xaccAccountSetAssociatedAccount*assertion*GNC_IS_ACCOUNT(acc)*");
+    xaccAccountSetAssociatedAccount (nullptr, "test", account);
+    g_test_assert_expected_messages();
+
+    xaccAccountSetAssociatedAccount (account, "test", account);
+    g_assert_true (xaccAccountGetAssociatedAccount (account, "test") == account);
+
+    xaccAccountSetAssociatedAccount (account, "test", nullptr);
+    g_assert_null (xaccAccountGetAssociatedAccount (account, "test"));
+
     // Balance Limits getter/setter
     g_assert_true (xaccAccountGetHigherBalanceLimit (account, &balance_limit) == false);
     g_assert_true (xaccAccountGetLowerBalanceLimit (account, &balance_limit) == false);



Summary of changes:
 gnucash/gnome/assistant-stock-transaction.cpp | 52 ++++++++++++++++++---------
 libgnucash/engine/Account.cpp                 | 50 ++++++++++++++++++++++++++
 libgnucash/engine/Account.h                   |  8 +++++
 libgnucash/engine/test/utest-Account.cpp      | 19 ++++++++++
 4 files changed, 113 insertions(+), 16 deletions(-)



More information about the gnucash-changes mailing list