gnucash stable: Multiple changes pushed
Christopher Lam
clam at code.gnucash.org
Mon Jun 30 10:48:44 EDT 2025
Updated via https://github.com/Gnucash/gnucash/commit/aa339b46 (commit)
via https://github.com/Gnucash/gnucash/commit/01366f42 (commit)
from https://github.com/Gnucash/gnucash/commit/eeedd7bf (commit)
commit aa339b4674a273d6f62485bb1a82b3d5c2e3c9a8
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Sun Jun 22 09:26:36 2025 +0800
[Transaction.cpp] use g_list_copy_deep
diff --git a/libgnucash/engine/Transaction.cpp b/libgnucash/engine/Transaction.cpp
index 7379ea9a35..830dd4f6e7 100644
--- a/libgnucash/engine/Transaction.cpp
+++ b/libgnucash/engine/Transaction.cpp
@@ -595,19 +595,12 @@ static Transaction *
dupe_trans (const Transaction *from)
{
Transaction *to;
- GList *node;
-
to = GNC_TRANSACTION(g_object_new (GNC_TYPE_TRANSACTION, nullptr));
CACHE_REPLACE (to->num, from->num);
CACHE_REPLACE (to->description, from->description);
- to->splits = g_list_copy (from->splits);
- for (node = to->splits; node; node = node->next)
- {
- node->data = xaccDupeSplit (GNC_SPLIT(node->data));
- }
-
+ to->splits = g_list_copy_deep (from->splits, (GCopyFunc)xaccDupeSplit, nullptr);
to->date_entered = from->date_entered;
to->date_posted = from->date_posted;
qof_instance_copy_version(to, from);
commit 01366f425fa2ebe70152de7bd994558699e028fa
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Sat Jun 28 23:09:22 2025 +0800
[gtest-load-and-test-datafile.cpp] add example .gnucash to test contents
seed xml datafile to test stability of XML serialization routines
diff --git a/libgnucash/backend/xml/test/CMakeLists.txt b/libgnucash/backend/xml/test/CMakeLists.txt
index 81b5e72ea5..0e711a1c4a 100644
--- a/libgnucash/backend/xml/test/CMakeLists.txt
+++ b/libgnucash/backend/xml/test/CMakeLists.txt
@@ -38,6 +38,7 @@ set_local_dist(test_backend_xml_DIST_local
test-load-backend.cpp
test-load-example-account.cpp
gtest-load-save-files.cpp
+ gtest-xml-contents.cpp
test-load-xml2.cpp
test-real-data.sh
test-save-in-lang.cpp
@@ -69,6 +70,10 @@ target_compile_options(test-load-example-account PRIVATE -DU_SHOW_CPLUSPLUS_API=
add_xml_gtest(test-load-save-files gtest-load-save-files.cpp
GNC_TEST_FILES=${CMAKE_CURRENT_SOURCE_DIR}/test-files/load-save
)
+add_xml_gtest(test-xml-contents gtest-xml-contents.cpp
+ GNC_TEST_FILES=${CMAKE_CURRENT_SOURCE_DIR}/test-files/xml-contents
+)
+
add_xml_test(test-string-converters "test-string-converters.cpp")
add_xml_test(test-xml-account "test-xml-account.cpp;test-file-stuff.cpp")
add_xml_test(test-xml-commodity "test-xml-commodity.cpp;test-file-stuff.cpp")
diff --git a/libgnucash/backend/xml/test/gtest-xml-contents.cpp b/libgnucash/backend/xml/test/gtest-xml-contents.cpp
new file mode 100644
index 0000000000..e11204ad1d
--- /dev/null
+++ b/libgnucash/backend/xml/test/gtest-xml-contents.cpp
@@ -0,0 +1,204 @@
+/********************************************************************\
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+#include <glib.h>
+
+#include <config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <cashobjects.h>
+#include <TransLog.h>
+#include <gnc-engine.h>
+#include <gnc-lot.h>
+#include <gnc-prefs.h>
+#include <Account.hpp>
+#include <gnc-datetime.hpp>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcpp"
+#include <gtest/gtest.h>
+#pragma GCC diagnostic pop
+#include <unittest-support.h>
+
+#include "../gnc-backend-xml.h"
+#include "../io-gncxml-v2.h"
+
+#define GNC_LIB_NAME "gncmod-backend-xml"
+#define GNC_LIB_REL_PATH "xml"
+
+class LoadFile : public testing::Test
+{
+public:
+ static void SetUpTestSuite ()
+ {
+ g_setenv ("GNC_UNINSTALLED", "1", TRUE);
+ qof_init ();
+ cashobjects_register ();
+ ASSERT_TRUE(qof_load_backend_library (GNC_LIB_REL_PATH, GNC_LIB_NAME)) << "loading gnc-backend-xml GModule failed";
+ xaccLogDisable ();
+ }
+
+ static void TearDownTestSuite () { qof_close (); }
+};
+
+static QofBook*
+session_load (QofSession* session, const char* filename)
+{
+ if (!session || !filename) return nullptr;
+
+ qof_session_begin (session, filename, SESSION_READ_ONLY);
+ if (qof_session_get_error(session) != 0)
+ {
+ std::cerr << "Session begin failed: " << qof_session_get_error_message(session);
+ return nullptr;
+ }
+
+ qof_session_load(session, nullptr);
+ if (qof_session_get_error(session) != 0)
+ {
+ std::cerr << "Session begin failed: " << qof_session_get_error_message(session);
+ return nullptr;
+ }
+
+ return qof_session_get_book(session);
+}
+
+TEST_F(LoadFile, LoadAndVerifyKVP)
+{
+ auto location{g_getenv ("GNC_TEST_FILES")};
+ if (!location)
+ location = "test-files/load-save";
+ auto filename{"xml-datafile.gnucash"};
+ std::shared_ptr<gchar> to_open{g_build_filename (location, filename, (gchar*)nullptr), g_free};
+ std::shared_ptr<QofSession> session{qof_session_new(qof_book_new()), qof_session_destroy};
+ auto book{session_load (session.get(), to_open.get())};
+ ASSERT_NE(book, nullptr);
+
+ auto bank_acct = gnc_account_lookup_by_name (gnc_book_get_root_account (book), "Bank");
+ ASSERT_TRUE (bank_acct != nullptr);
+
+ // THE FOLLOWING TESTS BANK ACCOUNT
+ const auto& bank_splitlist = xaccAccountGetSplits (bank_acct);
+ ASSERT_EQ (bank_splitlist.size(), static_cast<uint>(4));
+
+ // first split is from a regular transaction
+ auto bank_reg_split{bank_splitlist[0]};
+ auto bank_reg_txn{xaccSplitGetParent(bank_reg_split)};
+ EXPECT_STREQ (xaccTransGetDescription (bank_reg_txn), "income");
+ EXPECT_STREQ (xaccTransGetNotes (bank_reg_txn), "notes");
+ EXPECT_STREQ (xaccTransGetNum (bank_reg_txn), "num");
+ EXPECT_STREQ (xaccTransGetDocLink (bank_reg_txn), "https://www.gnucash.org/");
+ EXPECT_TRUE (gnc_numeric_equal (xaccSplitGetAmount (bank_reg_split), gnc_numeric_create (200, 1)));
+ EXPECT_TRUE (gnc_numeric_equal (xaccSplitGetValue (bank_reg_split), gnc_numeric_create (200, 1)));
+ EXPECT_EQ (GncDateTime(xaccTransGetDate(bank_reg_txn)).format_iso8601(), "2025-01-01 10:59:00");
+ EXPECT_EQ (xaccTransGetTxnType (bank_reg_txn), TXN_TYPE_NONE);
+ EXPECT_FALSE (xaccTransGetIsClosingTxn (bank_reg_txn));
+ EXPECT_STREQ (xaccTransGetReadOnly (bank_reg_txn), nullptr);
+
+ // 2nd split is a payment split
+ auto bank_pmt_split{bank_splitlist[1]};
+ auto bank_pmt_txn{xaccSplitGetParent(bank_pmt_split)};
+ EXPECT_STREQ (xaccTransGetDescription (bank_pmt_txn), "customer-name");
+ EXPECT_STREQ (xaccTransGetNotes (bank_pmt_txn), NULL);
+ EXPECT_STREQ (xaccTransGetNum (bank_pmt_txn), "pmt-num");
+ EXPECT_STREQ (xaccTransGetDocLink (bank_pmt_txn), nullptr);
+ EXPECT_EQ (GncDateTime(xaccTransGetDate(bank_pmt_txn)).format_iso8601(), "2025-02-12 10:59:00");
+ EXPECT_EQ (xaccTransGetTxnType (bank_pmt_txn), TXN_TYPE_PAYMENT);
+ EXPECT_TRUE (gnc_numeric_equal (xaccSplitGetAmount (bank_pmt_split), gnc_numeric_create (194, 100)));
+ EXPECT_TRUE (gnc_numeric_equal (xaccSplitGetValue (bank_pmt_split), gnc_numeric_create (194, 100)));
+ EXPECT_STREQ (xaccTransGetReadOnly (bank_pmt_txn), nullptr);
+ EXPECT_STREQ (xaccTransGetVoidReason (bank_pmt_txn), nullptr);
+
+ // 3nd split is a voided split
+ auto bank_voided_split{bank_splitlist[2]};
+ auto bank_voided_txn{xaccSplitGetParent(bank_voided_split)};
+ EXPECT_STREQ (xaccTransGetDescription (bank_voided_txn), "another income voided");
+ EXPECT_STREQ (xaccTransGetNotes (bank_voided_txn), "Voided transaction");
+ EXPECT_STREQ (xaccTransGetNum (bank_voided_txn), "");
+ EXPECT_STREQ (xaccTransGetDocLink (bank_voided_txn), nullptr);
+ EXPECT_EQ (GncDateTime(xaccTransGetDate(bank_voided_txn)).format_iso8601(), "2025-03-01 10:59:00");
+ EXPECT_EQ (xaccTransGetTxnType (bank_voided_txn), TXN_TYPE_NONE);
+ EXPECT_TRUE (gnc_numeric_equal (xaccSplitGetAmount (bank_voided_split), gnc_numeric_create (0, 100)));
+ EXPECT_TRUE (gnc_numeric_equal (xaccSplitGetValue (bank_voided_split), gnc_numeric_create (0, 100)));
+ EXPECT_STREQ (xaccTransGetReadOnly (bank_voided_txn), "Transaction Voided");
+ EXPECT_STREQ (xaccTransGetVoidReason (bank_voided_txn), "cancelled");
+
+ // 4th split is the 2nd payment reversal txn, reversed
+ auto bank_pmt_rev_split{bank_splitlist[3]};
+ auto bank_pmt_rev_txn{xaccSplitGetParent(bank_pmt_rev_split)};
+ EXPECT_STREQ (xaccTransGetDescription (bank_pmt_rev_txn), "customer-name");
+ EXPECT_STREQ (xaccTransGetNotes (bank_pmt_rev_txn), nullptr);
+ EXPECT_STREQ (xaccTransGetNum (bank_pmt_rev_txn), "pmt-num");
+ EXPECT_STREQ (xaccTransGetDocLink (bank_pmt_rev_txn), nullptr);
+ EXPECT_EQ (GncDateTime(xaccTransGetDate(bank_pmt_rev_txn)).format_iso8601(), "2025-04-01 10:59:00");
+ EXPECT_EQ (xaccTransGetTxnType (bank_pmt_rev_txn), TXN_TYPE_PAYMENT);
+ EXPECT_EQ (xaccTransGetReversedBy (bank_pmt_txn), bank_pmt_rev_txn);
+ EXPECT_TRUE (gnc_numeric_equal (xaccSplitGetAmount (bank_pmt_rev_split), gnc_numeric_create (-194, 100)));
+ EXPECT_TRUE (gnc_numeric_equal (xaccSplitGetValue (bank_pmt_rev_split), gnc_numeric_create (-194, 100)));
+ EXPECT_STREQ (xaccTransGetReadOnly (bank_pmt_rev_txn), nullptr);
+ EXPECT_STREQ (xaccTransGetVoidReason (bank_pmt_rev_txn), nullptr);
+
+ // THE FOLLOWING TESTS AR ACCOUNT
+ auto AR_acct{gnc_account_lookup_by_name (gnc_book_get_root_account (book), "AReceivable")};
+ ASSERT_TRUE (AR_acct != nullptr);
+
+ const auto& AR_splitlist{xaccAccountGetSplits (AR_acct)};
+ ASSERT_EQ (AR_splitlist.size(), static_cast<uint>(3));
+
+ // 1st split is invoice posting txn
+ auto inv_post_txn{xaccSplitGetParent(AR_splitlist[0])};
+ EXPECT_STREQ (xaccTransGetDescription (inv_post_txn), "customer-name");
+ EXPECT_STREQ (xaccTransGetNotes (inv_post_txn), nullptr);
+ EXPECT_STREQ (xaccTransGetNum (inv_post_txn), "000001");
+ EXPECT_EQ (GncDateTime(xaccTransGetDate(inv_post_txn)).format_iso8601(), "2025-02-01 10:59:00");
+ EXPECT_EQ (xaccTransGetTxnType (inv_post_txn), TXN_TYPE_INVOICE);
+ EXPECT_EQ (GncDateTime(xaccTransRetDateDue(inv_post_txn)).format_iso8601(), "2025-02-14 10:59:00");
+ EXPECT_FALSE (xaccTransGetIsClosingTxn (inv_post_txn));
+ EXPECT_STREQ (xaccTransGetReadOnly (inv_post_txn), "Generated from an invoice. Try unposting the invoice.");
+
+ // test invoice lot properties
+ auto inv_lot{xaccSplitGetLot (AR_splitlist[0])};
+ EXPECT_STREQ (gnc_lot_get_title (inv_lot), "Invoice 000001");
+ EXPECT_STREQ (gnc_lot_get_notes (inv_lot), nullptr);
+
+ // 2nd split is from payment txn, should be identical to bank payment txn
+ auto inv_pmt_txn{xaccSplitGetParent(AR_splitlist[1])};
+ EXPECT_EQ (inv_pmt_txn, bank_pmt_txn);
+
+ // THE FOLLOWING TESTS CLOSING ACCOUNT
+ auto close_acct{gnc_account_lookup_by_name (gnc_book_get_root_account (book), "Closing")};
+ ASSERT_TRUE (close_acct != nullptr);
+
+ const auto& close_splitlist{xaccAccountGetSplits (close_acct)};
+ ASSERT_EQ (close_splitlist.size(), static_cast<uint>(1));
+
+ // 3rd split is a closing txn
+ auto closing_txn{xaccSplitGetParent(close_splitlist[0])};
+ EXPECT_STREQ (xaccTransGetDescription (closing_txn), "Closing Txn");
+ EXPECT_STREQ (xaccTransGetNotes (closing_txn), nullptr);
+ EXPECT_STREQ (xaccTransGetNum (closing_txn), "");
+ EXPECT_EQ (xaccTransGetTxnType (closing_txn), TXN_TYPE_NONE);
+ EXPECT_EQ (GncDateTime(xaccTransGetDate(closing_txn)).format_iso8601(), "2025-03-01 10:59:00");
+ EXPECT_EQ (GncDateTime(xaccTransRetDateDue(closing_txn)).format_iso8601(), "2025-03-01 10:59:00");
+ EXPECT_TRUE (xaccTransGetIsClosingTxn (closing_txn));
+ EXPECT_STREQ (xaccTransGetReadOnly (closing_txn), nullptr);
+
+ qof_session_end(session.get());
+}
diff --git a/libgnucash/backend/xml/test/test-files/CMakeLists.txt b/libgnucash/backend/xml/test/test-files/CMakeLists.txt
index 126fc36391..269a9e5b90 100644
--- a/libgnucash/backend/xml/test/test-files/CMakeLists.txt
+++ b/libgnucash/backend/xml/test/test-files/CMakeLists.txt
@@ -1,6 +1,9 @@
add_subdirectory(load-save)
+add_subdirectory(xml-contents)
add_subdirectory(xml2)
set_local_dist(test_backend_xml_test_files_DIST_local CMakeLists.txt )
-set(test_backend_xml_test_files_DIST ${test_backend_xml_test_files_DIST_local} ${load_save_DIST} ${xml2_DIST} PARENT_SCOPE)
+set(test_backend_xml_test_files_DIST ${test_backend_xml_test_files_DIST_local} ${load_save_DIST} ${xml2_DIST}
+ ${xml_contents_DIST}
+ PARENT_SCOPE)
diff --git a/libgnucash/backend/xml/test/test-files/xml-contents/CMakeLists.txt b/libgnucash/backend/xml/test/test-files/xml-contents/CMakeLists.txt
new file mode 100644
index 0000000000..6419e75608
--- /dev/null
+++ b/libgnucash/backend/xml/test/test-files/xml-contents/CMakeLists.txt
@@ -0,0 +1,4 @@
+set_dist_list(xml_contents_DIST
+ xml-datafile.gnucash
+ CMakeLists.txt
+)
diff --git a/libgnucash/backend/xml/test/test-files/xml-contents/xml-datafile.gnucash b/libgnucash/backend/xml/test/test-files/xml-contents/xml-datafile.gnucash
new file mode 100644
index 0000000000..2e3863c765
--- /dev/null
+++ b/libgnucash/backend/xml/test/test-files/xml-contents/xml-datafile.gnucash
@@ -0,0 +1,595 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<gnc-v2
+ xmlns:gnc="http://www.gnucash.org/XML/gnc"
+ xmlns:act="http://www.gnucash.org/XML/act"
+ xmlns:book="http://www.gnucash.org/XML/book"
+ xmlns:cd="http://www.gnucash.org/XML/cd"
+ xmlns:cmdty="http://www.gnucash.org/XML/cmdty"
+ xmlns:price="http://www.gnucash.org/XML/price"
+ xmlns:slot="http://www.gnucash.org/XML/slot"
+ xmlns:split="http://www.gnucash.org/XML/split"
+ xmlns:sx="http://www.gnucash.org/XML/sx"
+ xmlns:trn="http://www.gnucash.org/XML/trn"
+ xmlns:ts="http://www.gnucash.org/XML/ts"
+ xmlns:fs="http://www.gnucash.org/XML/fs"
+ xmlns:bgt="http://www.gnucash.org/XML/bgt"
+ xmlns:recurrence="http://www.gnucash.org/XML/recurrence"
+ xmlns:lot="http://www.gnucash.org/XML/lot"
+ xmlns:addr="http://www.gnucash.org/XML/addr"
+ xmlns:billterm="http://www.gnucash.org/XML/billterm"
+ xmlns:bt-days="http://www.gnucash.org/XML/bt-days"
+ xmlns:bt-prox="http://www.gnucash.org/XML/bt-prox"
+ xmlns:cust="http://www.gnucash.org/XML/cust"
+ xmlns:employee="http://www.gnucash.org/XML/employee"
+ xmlns:entry="http://www.gnucash.org/XML/entry"
+ xmlns:invoice="http://www.gnucash.org/XML/invoice"
+ xmlns:job="http://www.gnucash.org/XML/job"
+ xmlns:order="http://www.gnucash.org/XML/order"
+ xmlns:owner="http://www.gnucash.org/XML/owner"
+ xmlns:taxtable="http://www.gnucash.org/XML/taxtable"
+ xmlns:tte="http://www.gnucash.org/XML/tte"
+ xmlns:vendor="http://www.gnucash.org/XML/vendor">
+<gnc:count-data cd:type="book">1</gnc:count-data>
+<gnc:book version="2.0.0">
+<book:id type="guid">f70b5dc6711143939c0dd7ae25e2e773</book:id>
+<book:slots>
+ <slot>
+ <slot:key>counters</slot:key>
+ <slot:value type="frame">
+ <slot>
+ <slot:key>gncCustomer</slot:key>
+ <slot:value type="integer">1</slot:value>
+ </slot>
+ <slot>
+ <slot:key>gncInvoice</slot:key>
+ <slot:value type="integer">1</slot:value>
+ </slot>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>features</slot:key>
+ <slot:value type="frame">
+ <slot>
+ <slot:key>Register sort and filter settings stored in .gcm file</slot:key>
+ <slot:value type="string">Store the register sort and filter settings in .gcm metadata file (requires at least GnuCash 3.3)</slot:value>
+ </slot>
+ <slot>
+ <slot:key>Use a dedicated opening balance account identified by an 'equity-type' slot</slot:key>
+ <slot:value type="string">Use a dedicated opening balance account identified by an 'equity-type' slot (requires at least Gnucash 4.3)</slot:value>
+ </slot>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>remove-color-not-set-slots</slot:key>
+ <slot:value type="string">true</slot:value>
+ </slot>
+</book:slots>
+<gnc:count-data cd:type="commodity">1</gnc:count-data>
+<gnc:count-data cd:type="account">5</gnc:count-data>
+<gnc:count-data cd:type="transaction">6</gnc:count-data>
+<gnc:count-data cd:type="gnc:GncCustomer">1</gnc:count-data>
+<gnc:count-data cd:type="gnc:GncEntry">1</gnc:count-data>
+<gnc:count-data cd:type="gnc:GncInvoice">1</gnc:count-data>
+<gnc:commodity version="2.0.0">
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ <cmdty:get_quotes/>
+ <cmdty:quote_source>currency</cmdty:quote_source>
+ <cmdty:quote_tz/>
+</gnc:commodity>
+<gnc:commodity version="2.0.0">
+ <cmdty:space>template</cmdty:space>
+ <cmdty:id>template</cmdty:id>
+ <cmdty:name>template</cmdty:name>
+ <cmdty:xcode>template</cmdty:xcode>
+ <cmdty:fraction>1</cmdty:fraction>
+</gnc:commodity>
+<gnc:account version="2.0.0">
+ <act:name>Root Account</act:name>
+ <act:id type="guid">ea1d654fedbf4d4c88be7df1b3e8be2a</act:id>
+ <act:type>ROOT</act:type>
+</gnc:account>
+<gnc:account version="2.0.0">
+ <act:name>Bank</act:name>
+ <act:id type="guid">0d0c14d1661b46819c18319c21dc2666</act:id>
+ <act:type>BANK</act:type>
+ <act:commodity>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </act:commodity>
+ <act:commodity-scu>100</act:commodity-scu>
+ <act:slots>
+ <slot>
+ <slot:key>balance-limit</slot:key>
+ <slot:value type="frame"/>
+ </slot>
+ </act:slots>
+ <act:parent type="guid">ea1d654fedbf4d4c88be7df1b3e8be2a</act:parent>
+</gnc:account>
+<gnc:account version="2.0.0">
+ <act:name>Income</act:name>
+ <act:id type="guid">5fb86abd10e94abba7463655767a5e63</act:id>
+ <act:type>INCOME</act:type>
+ <act:commodity>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </act:commodity>
+ <act:commodity-scu>100</act:commodity-scu>
+ <act:slots>
+ <slot>
+ <slot:key>balance-limit</slot:key>
+ <slot:value type="frame"/>
+ </slot>
+ </act:slots>
+ <act:parent type="guid">ea1d654fedbf4d4c88be7df1b3e8be2a</act:parent>
+</gnc:account>
+<gnc:account version="2.0.0">
+ <act:name>AReceivable</act:name>
+ <act:id type="guid">0656224544884e8e8196f23af8e67a1e</act:id>
+ <act:type>RECEIVABLE</act:type>
+ <act:commodity>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </act:commodity>
+ <act:commodity-scu>100</act:commodity-scu>
+ <act:slots>
+ <slot>
+ <slot:key>balance-limit</slot:key>
+ <slot:value type="frame"/>
+ </slot>
+ </act:slots>
+ <act:parent type="guid">ea1d654fedbf4d4c88be7df1b3e8be2a</act:parent>
+ <act:lots>
+ <gnc:lot version="2.0.0">
+ <lot:id type="guid">73ab1ddf8d4943799c6705e1813ae582</lot:id>
+ <lot:slots>
+ <slot>
+ <slot:key>gncInvoice</slot:key>
+ <slot:value type="frame">
+ <slot>
+ <slot:key>invoice-guid</slot:key>
+ <slot:value type="guid">2d4e6dbfba6949abb6e4e1b0fe0ad54a</slot:value>
+ </slot>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>title</slot:key>
+ <slot:value type="string">Invoice 000001</slot:value>
+ </slot>
+ </lot:slots>
+ </gnc:lot>
+ </act:lots>
+</gnc:account>
+<gnc:account version="2.0.0">
+ <act:name>Closing</act:name>
+ <act:id type="guid">5ec7e02aafcf4e438cab06530ebaffd2</act:id>
+ <act:type>EQUITY</act:type>
+ <act:commodity>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </act:commodity>
+ <act:commodity-scu>100</act:commodity-scu>
+ <act:slots>
+ <slot>
+ <slot:key>balance-limit</slot:key>
+ <slot:value type="frame"/>
+ </slot>
+ </act:slots>
+ <act:parent type="guid">ea1d654fedbf4d4c88be7df1b3e8be2a</act:parent>
+</gnc:account>
+<gnc:transaction version="2.0.0">
+ <trn:id type="guid">e0f0c58c19d9460a908e4f76e065cf50</trn:id>
+ <trn:currency>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </trn:currency>
+ <trn:num>num</trn:num>
+ <trn:date-posted>
+ <ts:date>2025-01-01 10:59:00 +0000</ts:date>
+ </trn:date-posted>
+ <trn:date-entered>
+ <ts:date>2025-06-28 13:27:50 +0000</ts:date>
+ </trn:date-entered>
+ <trn:description>income</trn:description>
+ <trn:slots>
+ <slot>
+ <slot:key>assoc_uri</slot:key>
+ <slot:value type="string">https://www.gnucash.org/</slot:value>
+ </slot>
+ <slot>
+ <slot:key>date-posted</slot:key>
+ <slot:value type="gdate">
+ <gdate>2025-01-01</gdate>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>notes</slot:key>
+ <slot:value type="string">notes</slot:value>
+ </slot>
+ </trn:slots>
+ <trn:splits>
+ <trn:split>
+ <split:id type="guid">1a3f6ea60fb6496183ee6e4fab152c51</split:id>
+ <split:action>Action</split:action>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>20000/100</split:value>
+ <split:quantity>20000/100</split:quantity>
+ <split:account type="guid">0d0c14d1661b46819c18319c21dc2666</split:account>
+ </trn:split>
+ <trn:split>
+ <split:id type="guid">ccb98b52387a4e17a84ffad4e836e108</split:id>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>-20000/100</split:value>
+ <split:quantity>-20000/100</split:quantity>
+ <split:account type="guid">5fb86abd10e94abba7463655767a5e63</split:account>
+ </trn:split>
+ </trn:splits>
+</gnc:transaction>
+<gnc:transaction version="2.0.0">
+ <trn:id type="guid">31f65079a2f449cab30f17ff5a88c4e1</trn:id>
+ <trn:currency>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </trn:currency>
+ <trn:num>pmt-num</trn:num>
+ <trn:date-posted>
+ <ts:date>2025-02-12 10:59:00 +0000</ts:date>
+ </trn:date-posted>
+ <trn:date-entered>
+ <ts:date>2025-06-28 15:05:43 +0000</ts:date>
+ </trn:date-entered>
+ <trn:description>customer-name</trn:description>
+ <trn:slots>
+ <slot>
+ <slot:key>reversed-by</slot:key>
+ <slot:value type="guid">5843eb8d60d24e589eee7fca998c1e83</slot:value>
+ </slot>
+ <slot>
+ <slot:key>trans-txn-type</slot:key>
+ <slot:value type="string">P</slot:value>
+ </slot>
+ </trn:slots>
+ <trn:splits>
+ <trn:split>
+ <split:id type="guid">2d8a86ad48314d4488a3150d34a680c5</split:id>
+ <split:memo>pmt-memo</split:memo>
+ <split:action>Payment</split:action>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>194/100</split:value>
+ <split:quantity>194/100</split:quantity>
+ <split:account type="guid">0d0c14d1661b46819c18319c21dc2666</split:account>
+ </trn:split>
+ <trn:split>
+ <split:id type="guid">7800a00db0b94ef2aaa95039f3d27934</split:id>
+ <split:memo>pmt-memo</split:memo>
+ <split:action>Payment</split:action>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>-194/100</split:value>
+ <split:quantity>-194/100</split:quantity>
+ <split:account type="guid">0656224544884e8e8196f23af8e67a1e</split:account>
+ <split:lot type="guid">73ab1ddf8d4943799c6705e1813ae582</split:lot>
+ </trn:split>
+ </trn:splits>
+</gnc:transaction>
+<gnc:transaction version="2.0.0">
+ <trn:id type="guid">a74a070640fe471dbef879ee55a63fa4</trn:id>
+ <trn:currency>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </trn:currency>
+ <trn:date-posted>
+ <ts:date>2025-03-01 10:59:00 +0000</ts:date>
+ </trn:date-posted>
+ <trn:date-entered>
+ <ts:date>2025-06-29 15:32:13 +0000</ts:date>
+ </trn:date-entered>
+ <trn:description>another income voided</trn:description>
+ <trn:slots>
+ <slot>
+ <slot:key>date-posted</slot:key>
+ <slot:value type="gdate">
+ <gdate>2025-03-01</gdate>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>notes</slot:key>
+ <slot:value type="string">Voided transaction</slot:value>
+ </slot>
+ <slot>
+ <slot:key>trans-read-only</slot:key>
+ <slot:value type="string">Transaction Voided</slot:value>
+ </slot>
+ <slot>
+ <slot:key>void-reason</slot:key>
+ <slot:value type="string">cancelled</slot:value>
+ </slot>
+ <slot>
+ <slot:key>void-time</slot:key>
+ <slot:value type="string">2025-06-29 15:32:22</slot:value>
+ </slot>
+ </trn:slots>
+ <trn:splits>
+ <trn:split>
+ <split:id type="guid">77cc7eb8b6f142cb94518d94aa6f234f</split:id>
+ <split:reconciled-state>v</split:reconciled-state>
+ <split:value>0/100</split:value>
+ <split:quantity>0/100</split:quantity>
+ <split:account type="guid">0d0c14d1661b46819c18319c21dc2666</split:account>
+ <split:slots>
+ <slot>
+ <slot:key>void-former-amount</slot:key>
+ <slot:value type="numeric">3456/100</slot:value>
+ </slot>
+ <slot>
+ <slot:key>void-former-value</slot:key>
+ <slot:value type="numeric">3456/100</slot:value>
+ </slot>
+ </split:slots>
+ </trn:split>
+ <trn:split>
+ <split:id type="guid">a0d3f31ab7954c8a8870347abdc0d787</split:id>
+ <split:reconciled-state>v</split:reconciled-state>
+ <split:value>0/100</split:value>
+ <split:quantity>0/100</split:quantity>
+ <split:account type="guid">5fb86abd10e94abba7463655767a5e63</split:account>
+ <split:slots>
+ <slot>
+ <slot:key>void-former-amount</slot:key>
+ <slot:value type="numeric">-3456/100</slot:value>
+ </slot>
+ <slot>
+ <slot:key>void-former-value</slot:key>
+ <slot:value type="numeric">-3456/100</slot:value>
+ </slot>
+ </split:slots>
+ </trn:split>
+ </trn:splits>
+</gnc:transaction>
+<gnc:transaction version="2.0.0">
+ <trn:id type="guid">5843eb8d60d24e589eee7fca998c1e83</trn:id>
+ <trn:currency>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </trn:currency>
+ <trn:num>pmt-num</trn:num>
+ <trn:date-posted>
+ <ts:date>2025-04-01 10:59:00 +0000</ts:date>
+ </trn:date-posted>
+ <trn:date-entered>
+ <ts:date>2025-06-29 15:41:00 +0000</ts:date>
+ </trn:date-entered>
+ <trn:description>customer-name</trn:description>
+ <trn:slots>
+ <slot>
+ <slot:key>date-posted</slot:key>
+ <slot:value type="gdate">
+ <gdate>2025-04-01</gdate>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>trans-txn-type</slot:key>
+ <slot:value type="string">P</slot:value>
+ </slot>
+ </trn:slots>
+ <trn:splits>
+ <trn:split>
+ <split:id type="guid">120d972af0c14e2e8848bcff6a156363</split:id>
+ <split:memo>pmt-memo</split:memo>
+ <split:action>Payment</split:action>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>194/100</split:value>
+ <split:quantity>194/100</split:quantity>
+ <split:account type="guid">0656224544884e8e8196f23af8e67a1e</split:account>
+ <split:lot type="guid">73ab1ddf8d4943799c6705e1813ae582</split:lot>
+ </trn:split>
+ <trn:split>
+ <split:id type="guid">4c7d0e0a00cc43dbad481d357c76db46</split:id>
+ <split:memo>pmt-memo</split:memo>
+ <split:action>Payment</split:action>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>-194/100</split:value>
+ <split:quantity>-194/100</split:quantity>
+ <split:account type="guid">0d0c14d1661b46819c18319c21dc2666</split:account>
+ </trn:split>
+ </trn:splits>
+</gnc:transaction>
+<gnc:transaction version="2.0.0">
+ <trn:id type="guid">372e0950eebc4bc0982768f6ad920c99</trn:id>
+ <trn:currency>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </trn:currency>
+ <trn:num>000001</trn:num>
+ <trn:date-posted>
+ <ts:date>2025-02-01 10:59:00 +0000</ts:date>
+ </trn:date-posted>
+ <trn:date-entered>
+ <ts:date>2025-06-28 15:03:49 +0000</ts:date>
+ </trn:date-entered>
+ <trn:description>customer-name</trn:description>
+ <trn:slots>
+ <slot>
+ <slot:key>date-posted</slot:key>
+ <slot:value type="gdate">
+ <gdate>2025-02-01</gdate>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>gncInvoice</slot:key>
+ <slot:value type="frame">
+ <slot>
+ <slot:key>invoice-guid</slot:key>
+ <slot:value type="guid">2d4e6dbfba6949abb6e4e1b0fe0ad54a</slot:value>
+ </slot>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>trans-date-due</slot:key>
+ <slot:value type="timespec">
+ <ts:date>2025-02-14 10:59:00 +0000</ts:date>
+ </slot:value>
+ </slot>
+ <slot>
+ <slot:key>trans-read-only</slot:key>
+ <slot:value type="string">Generated from an invoice. Try unposting the invoice.</slot:value>
+ </slot>
+ <slot>
+ <slot:key>trans-txn-type</slot:key>
+ <slot:value type="string">I</slot:value>
+ </slot>
+ </trn:slots>
+ <trn:splits>
+ <trn:split>
+ <split:id type="guid">a48caa6921c14aaa8e304649702cf195</split:id>
+ <split:memo>inv-desc</split:memo>
+ <split:action>Invoice</split:action>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>194/100</split:value>
+ <split:quantity>194/100</split:quantity>
+ <split:account type="guid">0656224544884e8e8196f23af8e67a1e</split:account>
+ <split:lot type="guid">73ab1ddf8d4943799c6705e1813ae582</split:lot>
+ </trn:split>
+ <trn:split>
+ <split:id type="guid">1746e3d2fc4a4561809803a36dbfefdc</split:id>
+ <split:memo>inv-desc</split:memo>
+ <split:action>Invoice</split:action>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>-194/100</split:value>
+ <split:quantity>-194/100</split:quantity>
+ <split:account type="guid">5fb86abd10e94abba7463655767a5e63</split:account>
+ </trn:split>
+ </trn:splits>
+</gnc:transaction>
+<gnc:transaction version="2.0.0">
+ <trn:id type="guid">c145788050934e00be3e28b2a15901aa</trn:id>
+ <trn:currency>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </trn:currency>
+ <trn:date-posted>
+ <ts:date>2025-03-01 10:59:00 +0000</ts:date>
+ </trn:date-posted>
+ <trn:date-entered>
+ <ts:date>2025-06-29 15:23:29 +0000</ts:date>
+ </trn:date-entered>
+ <trn:description>Closing Txn</trn:description>
+ <trn:slots>
+ <slot>
+ <slot:key>book_closing</slot:key>
+ <slot:value type="integer">1</slot:value>
+ </slot>
+ <slot>
+ <slot:key>date-posted</slot:key>
+ <slot:value type="gdate">
+ <gdate>2025-03-01</gdate>
+ </slot:value>
+ </slot>
+ </trn:slots>
+ <trn:splits>
+ <trn:split>
+ <split:id type="guid">583b1c39b0664eeebdf1165763defb91</split:id>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>20194/100</split:value>
+ <split:quantity>20194/100</split:quantity>
+ <split:account type="guid">5fb86abd10e94abba7463655767a5e63</split:account>
+ </trn:split>
+ <trn:split>
+ <split:id type="guid">e10d19734a1f435e8c191f7c830f68ff</split:id>
+ <split:reconciled-state>n</split:reconciled-state>
+ <split:value>-20194/100</split:value>
+ <split:quantity>-20194/100</split:quantity>
+ <split:account type="guid">5ec7e02aafcf4e438cab06530ebaffd2</split:account>
+ </trn:split>
+ </trn:splits>
+</gnc:transaction>
+<gnc:GncCustomer version="2.0.0">
+ <cust:guid type="guid">2e8b6716d9cb4d70b8b7bea13315f939</cust:guid>
+ <cust:name>customer-name</cust:name>
+ <cust:id>000001</cust:id>
+ <cust:addr version="2.0.0">
+ <addr:name>billing-name</addr:name>
+ <addr:addr1>addr1</addr:addr1>
+ <addr:addr2>addr2</addr:addr2>
+ <addr:addr3>addr3</addr:addr3>
+ <addr:addr4>addr4</addr:addr4>
+ <addr:phone>cust-phone</addr:phone>
+ <addr:fax>cust-fax</addr:fax>
+ <addr:email>cust-email</addr:email>
+ </cust:addr>
+ <cust:shipaddr version="2.0.0"/>
+ <cust:notes>cust-notes</cust:notes>
+ <cust:taxincluded>USEGLOBAL</cust:taxincluded>
+ <cust:active>1</cust:active>
+ <cust:discount>0/1</cust:discount>
+ <cust:credit>0/1</cust:credit>
+ <cust:currency>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </cust:currency>
+ <cust:use-tt>0</cust:use-tt>
+ <cust:slots>
+ <slot>
+ <slot:key>last-posted-to-acct</slot:key>
+ <slot:value type="guid">0656224544884e8e8196f23af8e67a1e</slot:value>
+ </slot>
+ <slot>
+ <slot:key>payment</slot:key>
+ <slot:value type="frame">
+ <slot>
+ <slot:key>last_acct</slot:key>
+ <slot:value type="guid">0d0c14d1661b46819c18319c21dc2666</slot:value>
+ </slot>
+ </slot:value>
+ </slot>
+ </cust:slots>
+</gnc:GncCustomer>
+<gnc:GncEntry version="2.0.0">
+ <entry:guid type="guid">81bb7b390a6240b4bab220f1bed4ebbb</entry:guid>
+ <entry:date>
+ <ts:date>2025-02-01 04:00:00 +0000</ts:date>
+ </entry:date>
+ <entry:entered>
+ <ts:date>2025-06-28 15:03:18 +0000</ts:date>
+ </entry:entered>
+ <entry:description>entry-desc</entry:description>
+ <entry:qty>1/1</entry:qty>
+ <entry:i-acct type="guid">5fb86abd10e94abba7463655767a5e63</entry:i-acct>
+ <entry:i-price>2/1</entry:i-price>
+ <entry:i-discount>3/1</entry:i-discount>
+ <entry:invoice type="guid">2d4e6dbfba6949abb6e4e1b0fe0ad54a</entry:invoice>
+ <entry:i-disc-type>PERCENT</entry:i-disc-type>
+ <entry:i-disc-how>PRETAX</entry:i-disc-how>
+ <entry:i-taxable>0</entry:i-taxable>
+ <entry:i-taxincluded>0</entry:i-taxincluded>
+</gnc:GncEntry>
+<gnc:GncInvoice version="2.0.0">
+ <invoice:guid type="guid">2d4e6dbfba6949abb6e4e1b0fe0ad54a</invoice:guid>
+ <invoice:id>000001</invoice:id>
+ <invoice:owner version="2.0.0">
+ <owner:type>gncCustomer</owner:type>
+ <owner:id type="guid">2e8b6716d9cb4d70b8b7bea13315f939</owner:id>
+ </invoice:owner>
+ <invoice:opened>
+ <ts:date>2025-02-01 10:59:00 +0000</ts:date>
+ </invoice:opened>
+ <invoice:posted>
+ <ts:date>2025-02-01 10:59:00 +0000</ts:date>
+ </invoice:posted>
+ <invoice:active>1</invoice:active>
+ <invoice:posttxn type="guid">372e0950eebc4bc0982768f6ad920c99</invoice:posttxn>
+ <invoice:postlot type="guid">73ab1ddf8d4943799c6705e1813ae582</invoice:postlot>
+ <invoice:postacc type="guid">0656224544884e8e8196f23af8e67a1e</invoice:postacc>
+ <invoice:currency>
+ <cmdty:space>CURRENCY</cmdty:space>
+ <cmdty:id>AUD</cmdty:id>
+ </invoice:currency>
+ <invoice:slots>
+ <slot>
+ <slot:key>credit-note</slot:key>
+ <slot:value type="integer">0</slot:value>
+ </slot>
+ </invoice:slots>
+</gnc:GncInvoice>
+</gnc:book>
+</gnc-v2>
+
Summary of changes:
libgnucash/backend/xml/test/CMakeLists.txt | 5 +
libgnucash/backend/xml/test/gtest-xml-contents.cpp | 204 +++++++
.../backend/xml/test/test-files/CMakeLists.txt | 5 +-
.../test/test-files/xml-contents/CMakeLists.txt | 4 +
.../test-files/xml-contents/xml-datafile.gnucash | 595 +++++++++++++++++++++
libgnucash/engine/Transaction.cpp | 9 +-
6 files changed, 813 insertions(+), 9 deletions(-)
create mode 100644 libgnucash/backend/xml/test/gtest-xml-contents.cpp
create mode 100644 libgnucash/backend/xml/test/test-files/xml-contents/CMakeLists.txt
create mode 100644 libgnucash/backend/xml/test/test-files/xml-contents/xml-datafile.gnucash
More information about the gnucash-changes
mailing list