mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Merge branch 'account-splits-vector' into stable #1917
This commit is contained in:
commit
3d173681cc
@ -247,7 +247,7 @@ gnc_account_opening_balance_button_update (AccountWindow *aw, gnc_commodity *com
|
||||
{
|
||||
Account *account = aw_get_account (aw);
|
||||
Account *ob_account = gnc_account_lookup_by_opening_balance (gnc_book_get_root_account (aw->book), commodity);
|
||||
gboolean has_splits = (xaccAccountGetSplitList (account) != NULL);
|
||||
gboolean has_splits = (xaccAccountGetSplitsSize (account) != 0);
|
||||
|
||||
if (aw->type != ACCT_TYPE_EQUITY)
|
||||
{
|
||||
@ -1614,7 +1614,7 @@ gnc_account_window_create (GtkWindow *parent, AccountWindow *aw)
|
||||
gtk_box_pack_start (GTK_BOX(box), aw->commodity_edit, TRUE, TRUE, 0);
|
||||
gtk_widget_show (aw->commodity_edit);
|
||||
// If the account has transactions, prevent changes by displaying a label and tooltip
|
||||
if (xaccAccountGetSplitList (aw_get_account (aw)) != NULL)
|
||||
if (xaccAccountGetSplitsSize (aw_get_account (aw)) != 0)
|
||||
{
|
||||
gtk_widget_set_tooltip_text (aw->commodity_edit, tt);
|
||||
gtk_widget_set_sensitive (aw->commodity_edit, FALSE);
|
||||
@ -1714,7 +1714,7 @@ gnc_account_window_create (GtkWindow *parent, AccountWindow *aw)
|
||||
// immutable if gnucash depends on details that would be lost/missing
|
||||
// if changing from/to such a type. At the time of this writing the
|
||||
// immutable types are AR, AP and trading types.
|
||||
if (xaccAccountGetSplitList (aw_get_account (aw)) != NULL)
|
||||
if (xaccAccountGetSplitsSize (aw_get_account (aw)) != 0)
|
||||
{
|
||||
GNCAccountType atype = xaccAccountGetType (aw_get_account (aw));
|
||||
compat_types = xaccAccountTypesCompatibleWith (atype);
|
||||
@ -2128,7 +2128,7 @@ gnc_ui_edit_account_window (GtkWindow *parent, Account *account)
|
||||
gnc_resume_gui_refresh ();
|
||||
|
||||
gtk_widget_show_all (aw->dialog);
|
||||
if (xaccAccountGetSplitList (account) != NULL)
|
||||
if (xaccAccountGetSplitsSize (account) != 0)
|
||||
gtk_widget_hide (aw->opening_balance_page);
|
||||
|
||||
parent_acct = gnc_account_get_parent (account);
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "gnc-ui.h"
|
||||
#include "Transaction.h"
|
||||
#include "Account.h"
|
||||
#include "Account.hpp"
|
||||
#include "engine-helpers.h"
|
||||
#include "QuickFill.h"
|
||||
#include <gnc-commodity.h>
|
||||
@ -472,10 +473,8 @@ gnc_xfer_dialog_reload_quickfill( XferDialog *xferData )
|
||||
gnc_quickfill_destroy( xferData->qf );
|
||||
xferData->qf = gnc_quickfill_new();
|
||||
|
||||
auto splitlist = xaccAccountGetSplitList( account );
|
||||
for ( GList *node = splitlist; node; node = node->next )
|
||||
for (auto split : xaccAccountGetSplits (account))
|
||||
{
|
||||
auto split = static_cast<Split *> (node->data);
|
||||
auto trans = xaccSplitGetParent (split);
|
||||
gnc_quickfill_insert( xferData->qf,
|
||||
xaccTransGetDescription (trans), QUICKFILL_LIFO);
|
||||
|
@ -143,6 +143,7 @@ gnc_autoclear_get_splits (Account *account, gnc_numeric toclear_value,
|
||||
else
|
||||
nc_list = g_list_prepend (nc_list, split);
|
||||
}
|
||||
g_list_free (acc_splits);
|
||||
|
||||
if (gnc_numeric_zero_p (toclear_value))
|
||||
{
|
||||
|
@ -1094,6 +1094,7 @@ RESTART:
|
||||
GList *splits = xaccAccountGetSplitList (acc);
|
||||
g_list_foreach (splits,
|
||||
(GFunc)gnc_sx_scrub_split_numerics, NULL);
|
||||
g_list_free (splits);
|
||||
}
|
||||
g_list_free (children);
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "Account.h"
|
||||
#include "Account.hpp"
|
||||
#include "Transaction.h"
|
||||
#include "engine-helpers.h"
|
||||
#include "dialog-utils.h"
|
||||
@ -1262,9 +1263,8 @@ StockAssistantModel::set_txn_type (guint type_idx)
|
||||
};
|
||||
|
||||
static void
|
||||
check_txn_date(GList* last_split_node, time64 txn_date, Logger& logger)
|
||||
check_txn_date(Split* last_split, time64 txn_date, Logger& logger)
|
||||
{
|
||||
auto last_split = static_cast<const Split *>(last_split_node->data);
|
||||
auto last_split_date = xaccTransGetDate(xaccSplitGetParent(last_split));
|
||||
if (txn_date <= last_split_date) {
|
||||
auto last_split_date_str = qof_print_date(last_split_date);
|
||||
@ -1301,9 +1301,9 @@ StockAssistantModel::generate_list_of_splits() {
|
||||
// transactions dated after the date specified, it is very likely
|
||||
// the later stock transactions will be invalidated. warn the user
|
||||
// to review them.
|
||||
auto last_split_node = g_list_last (xaccAccountGetSplitList (m_acct));
|
||||
if (last_split_node)
|
||||
check_txn_date(last_split_node, m_transaction_date, m_logger);
|
||||
auto splits{xaccAccountGetSplits (m_acct)};
|
||||
if (!splits.empty())
|
||||
check_txn_date(splits.back(), m_transaction_date, m_logger);
|
||||
|
||||
if (m_stock_entry->enabled() || m_stock_entry->has_amount())
|
||||
{
|
||||
|
@ -236,6 +236,7 @@ lv_show_splits_free (GNCLotViewer *lv)
|
||||
/* display list */
|
||||
gnc_split_viewer_fill(lv, lv->split_free_store, filtered_list);
|
||||
g_list_free (filtered_list);
|
||||
g_list_free (split_list);
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
|
@ -847,6 +847,7 @@ gnc_sxed_check_consistent (GncSxEditorDialog *sxed)
|
||||
g_hash_table_foreach (txns, set_sums_to_zero, NULL);
|
||||
|
||||
splitCount += g_list_length (splitList);
|
||||
g_list_free (splitList);
|
||||
|
||||
xaccAccountForEachTransaction (tmpl_acct, check_transaction_splits, &sd);
|
||||
|
||||
@ -1510,6 +1511,7 @@ schedXact_editor_populate (GncSxEditorDialog *sxed)
|
||||
splitReg = gnc_ledger_display_get_split_register (sxed->ledger);
|
||||
gnc_split_register_load (splitReg, splitList, NULL);
|
||||
} /* otherwise, use the existing stuff. */
|
||||
g_list_free (splitList);
|
||||
}
|
||||
|
||||
/* Update the example cal */
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "gnc-plugin-page-account-tree.h"
|
||||
#include "gnc-plugin-page-register.h"
|
||||
|
||||
#include "Account.hpp"
|
||||
#include "Scrub.h"
|
||||
#include "Scrub3.h"
|
||||
#include "ScrubBusiness.h"
|
||||
@ -1145,22 +1146,19 @@ static gpointer
|
||||
delete_account_helper (Account * account, gpointer data)
|
||||
{
|
||||
auto helper_res = static_cast<delete_helper_t*>(data);
|
||||
GList *splits;
|
||||
auto splits{xaccAccountGetSplits (account)};
|
||||
|
||||
splits = xaccAccountGetSplitList (account);
|
||||
if (splits)
|
||||
if (!splits.empty())
|
||||
{
|
||||
helper_res->has_splits = TRUE;
|
||||
while (splits)
|
||||
for (auto s : splits)
|
||||
{
|
||||
auto s = GNC_SPLIT(splits->data);
|
||||
Transaction *txn = xaccSplitGetParent (s);
|
||||
if (xaccTransGetReadOnly (txn))
|
||||
{
|
||||
helper_res->has_ro_splits = TRUE;
|
||||
break;
|
||||
}
|
||||
splits = splits->next;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1383,7 +1381,6 @@ account_delete_dialog (Account *account, GtkWindow *parent, Adopters* adopt)
|
||||
gchar *title = NULL;
|
||||
GtkBuilder *builder = gtk_builder_new();
|
||||
gchar *acct_name = gnc_account_get_full_name(account);
|
||||
GList* splits = xaccAccountGetSplitList(account);
|
||||
GList* filter = g_list_prepend(NULL, (gpointer)xaccAccountGetType(account));
|
||||
|
||||
if (!acct_name)
|
||||
@ -1416,7 +1413,7 @@ account_delete_dialog (Account *account, GtkWindow *parent, Adopters* adopt)
|
||||
account, FALSE);
|
||||
|
||||
// Does the selected account have splits
|
||||
if (splits)
|
||||
if (!xaccAccountGetSplits(account).empty())
|
||||
{
|
||||
delete_helper_t delete_res2 = { FALSE, FALSE };
|
||||
|
||||
@ -1537,8 +1534,7 @@ gnc_plugin_page_account_tree_cmd_delete_account (GSimpleAction *simple,
|
||||
}
|
||||
|
||||
// If no transaction or children just delete it.
|
||||
if (!(xaccAccountGetSplitList (account) != NULL ||
|
||||
gnc_account_n_children (account)))
|
||||
if (xaccAccountGetSplits (account).empty() && gnc_account_n_children (account) == 0)
|
||||
{
|
||||
do_delete_account (account, NULL, NULL, NULL);
|
||||
return;
|
||||
@ -1581,7 +1577,6 @@ confirm_delete_account (GSimpleAction *simple, GncPluginPageAccountTree *page,
|
||||
delete_helper_t delete_res)
|
||||
{
|
||||
Account *account = gnc_plugin_page_account_tree_get_current_account (page);
|
||||
GList* splits = xaccAccountGetSplitList(account);
|
||||
GtkWidget* window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
|
||||
gint response;
|
||||
|
||||
@ -1595,7 +1590,7 @@ confirm_delete_account (GSimpleAction *simple, GncPluginPageAccountTree *page,
|
||||
acct_name);
|
||||
g_free(acct_name);
|
||||
|
||||
if (splits)
|
||||
if (!xaccAccountGetSplits (account).empty())
|
||||
{
|
||||
if (ta)
|
||||
{
|
||||
|
@ -231,9 +231,8 @@ static void dump_acct (Account *acct)
|
||||
std::cout << '\n' << std::setw(20) << std::right << xaccAccountGetName (acct)
|
||||
<< " Bal=" << std::setw(10) << std::right << GncNumeric (xaccAccountGetBalance (acct))
|
||||
<< std::endl;
|
||||
for (auto n = xaccAccountGetSplitList (acct); n; n = n->next)
|
||||
for (auto s : xaccAccountGetSplits (acct))
|
||||
{
|
||||
auto s = static_cast<Split*>(n->data);
|
||||
bal += xaccSplitGetAmount (s);
|
||||
std::cout << std::setw(20) << std::right << GncDateTime (xaccTransGetDate (xaccSplitGetParent (s))).format_iso8601()
|
||||
<< " amt=" << std::setw(10) << std::right << GncNumeric (xaccSplitGetAmount (s))
|
||||
|
@ -37,6 +37,7 @@
|
||||
#endif
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "Account.hpp"
|
||||
#include "Scrub.h"
|
||||
#include "Scrub3.h"
|
||||
#include "dialog-account.h"
|
||||
@ -1621,10 +1622,8 @@ recn_set_watches_one_account (gpointer data, gpointer user_data)
|
||||
QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
|
||||
|
||||
/* add a watch on each unreconciled or cleared split for the account */
|
||||
GList *splits = xaccAccountGetSplitList (account);
|
||||
for (GList *node = splits; node; node = node->next)
|
||||
for (auto split : xaccAccountGetSplits (account))
|
||||
{
|
||||
auto split = GNC_SPLIT(node->data);
|
||||
Transaction *trans;
|
||||
char recn;
|
||||
|
||||
@ -1942,22 +1941,16 @@ recnWindowWithBalance (GtkWidget *parent, Account *account, gnc_numeric new_endi
|
||||
GtkWidget *box = gtk_statusbar_get_message_area (bar);
|
||||
GtkWidget *image = gtk_image_new_from_icon_name
|
||||
("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR);
|
||||
GList *splits = xaccAccountGetSplitList (account);
|
||||
|
||||
for (GList *n = splits; n; n = n->next)
|
||||
auto find_split = [statement_date](const Split *split)
|
||||
{ return (xaccSplitGetReconcile (split) == YREC &&
|
||||
xaccSplitGetDateReconciled (split) > statement_date); };
|
||||
|
||||
if (auto split = gnc_account_find_split (account, find_split, true))
|
||||
{
|
||||
auto split = GNC_SPLIT(n->data);
|
||||
time64 recn_date = xaccSplitGetDateReconciled (split);
|
||||
gchar *datestr, *recnstr;
|
||||
if ((xaccSplitGetReconcile (split) != YREC) ||
|
||||
(recn_date <= statement_date))
|
||||
continue;
|
||||
|
||||
datestr = qof_print_date (xaccTransGetDate (xaccSplitGetParent (split)));
|
||||
recnstr = qof_print_date (recn_date);
|
||||
auto datestr = qof_print_date (xaccTransGetDate (xaccSplitGetParent (split)));
|
||||
auto recnstr = qof_print_date (xaccSplitGetDateReconciled (split));
|
||||
PWARN ("split posting_date=%s, recn_date=%s", datestr, recnstr);
|
||||
g_free (datestr);
|
||||
g_free (recnstr);
|
||||
|
||||
gtk_statusbar_push (bar, context, _("WARNING! Account contains \
|
||||
splits whose reconcile date is after statement date. Reconciliation may be \
|
||||
@ -1970,7 +1963,9 @@ use Find Transactions to find them, unreconcile, and re-reconcile."));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX(box), image, FALSE, FALSE, 0);
|
||||
gtk_box_reorder_child (GTK_BOX(box), image, 0);
|
||||
break;
|
||||
|
||||
g_free (datestr);
|
||||
g_free (recnstr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2305,6 +2300,7 @@ find_payment_account(Account *account)
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (list);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "import-backend.h"
|
||||
#include "import-utilities.h"
|
||||
#include "Account.h"
|
||||
#include "Account.hpp"
|
||||
#include "Query.h"
|
||||
#include "gnc-engine.h"
|
||||
#include "engine-helpers.h"
|
||||
@ -996,9 +997,9 @@ hash_account_online_ids (Account *account)
|
||||
{
|
||||
auto acct_hash = g_hash_table_new_full
|
||||
(g_str_hash, g_str_equal, g_free, nullptr);
|
||||
for (GList *n = xaccAccountGetSplitList (account) ; n; n = n->next)
|
||||
for (auto split : xaccAccountGetSplits (account))
|
||||
{
|
||||
auto id = gnc_import_get_split_online_id (static_cast<Split *>(n->data));
|
||||
auto id = gnc_import_get_split_online_id (split);
|
||||
if (id && *id)
|
||||
g_hash_table_insert (acct_hash, (void*) id, GINT_TO_POINTER (1));
|
||||
}
|
||||
|
@ -44,6 +44,7 @@
|
||||
|
||||
#include "import-main-matcher.h"
|
||||
|
||||
#include "Account.hpp"
|
||||
#include "dialog-transfer.h"
|
||||
#include "dialog-utils.h"
|
||||
#include "gnc-glib-utils.h"
|
||||
@ -468,9 +469,8 @@ load_hash_tables (GNCImportMainMatcher *info)
|
||||
}
|
||||
for (GList *m = accounts_list; m; m = m->next)
|
||||
{
|
||||
for (GList *n = xaccAccountGetSplitList (static_cast<Account*>(m->data)); n; n = n->next)
|
||||
for (auto s : xaccAccountGetSplits (static_cast<Account*>(m->data)))
|
||||
{
|
||||
auto s = static_cast<const Split*>(n->data);
|
||||
const Transaction *t = xaccSplitGetParent (s);
|
||||
|
||||
const gchar *key = xaccTransGetDescription (t);
|
||||
|
@ -683,6 +683,7 @@ gnc_find_split_in_account_by_memo (Account *account, const char *memo,
|
||||
rv = split;
|
||||
}
|
||||
|
||||
g_list_free (splits);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "AccountP.hpp"
|
||||
#include "Account.hpp"
|
||||
#include "Split.h"
|
||||
#include "Transaction.h"
|
||||
#include "TransactionP.h"
|
||||
@ -331,7 +332,7 @@ gnc_account_init(Account* acc)
|
||||
priv->lower_balance_limit = {};
|
||||
priv->include_sub_account_balances = {};
|
||||
|
||||
priv->splits = nullptr;
|
||||
priv->splits.clear();
|
||||
priv->sort_dirty = FALSE;
|
||||
}
|
||||
|
||||
@ -1136,6 +1137,29 @@ xaccInitAccount (Account * acc, QofBook *book)
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
Split*
|
||||
gnc_account_find_split (const Account *acc, std::function<bool(const Split*)> predicate,
|
||||
bool reverse)
|
||||
{
|
||||
if (!GNC_IS_ACCOUNT (acc))
|
||||
return nullptr;
|
||||
|
||||
auto splits{GET_PRIVATE(acc)->splits};
|
||||
if (reverse)
|
||||
{
|
||||
auto latest = std::find_if(splits.rbegin(), splits.rend(), predicate);
|
||||
return (latest == splits.rend()) ? nullptr : *latest;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto earliest = std::find_if(splits.begin(), splits.end(), predicate);
|
||||
return (earliest == splits.end()) ? nullptr : *earliest;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
QofBook *
|
||||
gnc_account_get_book(const Account *account)
|
||||
{
|
||||
@ -1368,22 +1392,18 @@ xaccFreeAccount (Account *acc)
|
||||
/* NB there shouldn't be any splits by now ... they should
|
||||
* have been all been freed by CommitEdit(). We can remove this
|
||||
* check once we know the warning isn't occurring any more. */
|
||||
if (priv->splits)
|
||||
if (!priv->splits.empty())
|
||||
{
|
||||
GList *slist;
|
||||
PERR (" instead of calling xaccFreeAccount(), please call\n"
|
||||
" xaccAccountBeginEdit(); xaccAccountDestroy();\n");
|
||||
|
||||
qof_instance_reset_editlevel(acc);
|
||||
|
||||
slist = g_list_copy(priv->splits);
|
||||
for (lp = slist; lp; lp = lp->next)
|
||||
for (auto s : priv->splits)
|
||||
{
|
||||
Split *s = (Split *) lp->data;
|
||||
g_assert(xaccSplitGetAccount(s) == acc);
|
||||
xaccSplitDestroy (s);
|
||||
}
|
||||
g_list_free(slist);
|
||||
/* Nothing here (or in xaccAccountCommitEdit) nullptrs priv->splits, so this asserts every time.
|
||||
g_assert(priv->splits == nullptr);
|
||||
*/
|
||||
@ -1416,6 +1436,7 @@ xaccFreeAccount (Account *acc)
|
||||
priv->type = ACCT_TYPE_NONE;
|
||||
gnc_commodity_decrement_usage_count(priv->commodity);
|
||||
priv->commodity = nullptr;
|
||||
priv->splits.clear();
|
||||
|
||||
priv->balance_dirty = FALSE;
|
||||
priv->sort_dirty = FALSE;
|
||||
@ -1483,7 +1504,6 @@ xaccAccountCommitEdit (Account *acc)
|
||||
priv = GET_PRIVATE(acc);
|
||||
if (qof_instance_get_destroying(acc))
|
||||
{
|
||||
GList *lp, *slist;
|
||||
QofCollection *col;
|
||||
|
||||
qof_instance_increase_editlevel(acc);
|
||||
@ -1500,18 +1520,12 @@ xaccAccountCommitEdit (Account *acc)
|
||||
themselves will be destroyed by the transaction code */
|
||||
if (!qof_book_shutting_down(book))
|
||||
{
|
||||
slist = g_list_copy(priv->splits);
|
||||
for (lp = slist; lp; lp = lp->next)
|
||||
{
|
||||
Split *s = static_cast<Split *>(lp->data);
|
||||
for (auto s : priv->splits)
|
||||
xaccSplitDestroy (s);
|
||||
}
|
||||
g_list_free(slist);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_list_free(priv->splits);
|
||||
priv->splits = nullptr;
|
||||
priv->splits.clear();
|
||||
}
|
||||
|
||||
/* It turns out there's a case where this assertion does not hold:
|
||||
@ -1528,7 +1542,7 @@ xaccAccountCommitEdit (Account *acc)
|
||||
qof_collection_foreach(col, destroy_pending_splits_for_account, acc);
|
||||
|
||||
/* the lots should be empty by now */
|
||||
for (lp = priv->lots; lp; lp = lp->next)
|
||||
for (auto lp = priv->lots; lp; lp = lp->next)
|
||||
{
|
||||
GNCLot *lot = static_cast<GNCLot*>(lp->data);
|
||||
gnc_lot_destroy (lot);
|
||||
@ -1822,37 +1836,23 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
|
||||
/* no parent; always compare downwards. */
|
||||
|
||||
{
|
||||
GList *la = priv_aa->splits;
|
||||
GList *lb = priv_ab->splits;
|
||||
|
||||
if ((la && !lb) || (!la && lb))
|
||||
if (priv_aa->splits.size() != priv_ab->splits.size())
|
||||
{
|
||||
PWARN ("only one has splits");
|
||||
return FALSE;
|
||||
PWARN ("number of splits differs");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (la && lb)
|
||||
for (auto it_a = priv_aa->splits.begin(), it_b = priv_ab->splits.begin();
|
||||
it_a != priv_aa->splits.end() && it_b != priv_ab->splits.end();
|
||||
++it_a, ++it_b)
|
||||
{
|
||||
/* presume that the splits are in the same order */
|
||||
while (la && lb)
|
||||
{
|
||||
Split *sa = (Split *) la->data;
|
||||
Split *sb = (Split *) lb->data;
|
||||
Split *sa = *it_a;
|
||||
Split *sb = *it_b;
|
||||
|
||||
if (!xaccSplitEqual(sa, sb, check_guids, TRUE, FALSE))
|
||||
{
|
||||
PWARN ("splits differ");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
la = la->next;
|
||||
lb = lb->next;
|
||||
}
|
||||
|
||||
if ((la != nullptr) || (lb != nullptr))
|
||||
{
|
||||
PWARN ("number of splits differs");
|
||||
return(FALSE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1922,30 +1922,29 @@ gboolean gnc_account_get_defer_bal_computation (Account *acc)
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
static bool split_cmp_less (const Split* a, const Split* b)
|
||||
{
|
||||
return xaccSplitOrder (a, b) < 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gnc_account_insert_split (Account *acc, Split *s)
|
||||
{
|
||||
AccountPrivate *priv;
|
||||
GList *node;
|
||||
|
||||
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
|
||||
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
|
||||
|
||||
priv = GET_PRIVATE(acc);
|
||||
node = g_list_find(priv->splits, s);
|
||||
if (node)
|
||||
if (std::find (priv->splits.begin(), priv->splits.end(), s) != priv->splits.end())
|
||||
return FALSE;
|
||||
|
||||
priv->splits.push_back (s);
|
||||
|
||||
if (qof_instance_get_editlevel(acc) == 0)
|
||||
{
|
||||
priv->splits = g_list_insert_sorted(priv->splits, s,
|
||||
(GCompareFunc)xaccSplitOrder);
|
||||
}
|
||||
std::sort (priv->splits.begin(), priv->splits.end(), split_cmp_less);
|
||||
else
|
||||
{
|
||||
priv->splits = g_list_prepend(priv->splits, s);
|
||||
priv->sort_dirty = TRUE;
|
||||
}
|
||||
priv->sort_dirty = true;
|
||||
|
||||
//FIXME: find better event
|
||||
qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, nullptr);
|
||||
@ -1962,17 +1961,17 @@ gboolean
|
||||
gnc_account_remove_split (Account *acc, Split *s)
|
||||
{
|
||||
AccountPrivate *priv;
|
||||
GList *node;
|
||||
|
||||
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
|
||||
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
|
||||
|
||||
priv = GET_PRIVATE(acc);
|
||||
node = g_list_find(priv->splits, s);
|
||||
if (nullptr == node)
|
||||
|
||||
auto it = std::remove (priv->splits.begin(), priv->splits.end(), s);
|
||||
if (it == priv->splits.end())
|
||||
return FALSE;
|
||||
|
||||
priv->splits = g_list_delete_link(priv->splits, node);
|
||||
priv->splits.erase (it, priv->splits.end());
|
||||
//FIXME: find better event type
|
||||
qof_event_gen(&acc->inst, QOF_EVENT_MODIFY, nullptr);
|
||||
// And send the account-based event, too
|
||||
@ -1993,7 +1992,7 @@ xaccAccountSortSplits (Account *acc, gboolean force)
|
||||
priv = GET_PRIVATE(acc);
|
||||
if (!priv->sort_dirty || (!force && qof_instance_get_editlevel(acc) > 0))
|
||||
return;
|
||||
priv->splits = g_list_sort(priv->splits, (GCompareFunc)xaccSplitOrder);
|
||||
std::sort (priv->splits.begin(), priv->splits.end(), split_cmp_less);
|
||||
priv->sort_dirty = FALSE;
|
||||
priv->balance_dirty = TRUE;
|
||||
}
|
||||
@ -2166,7 +2165,7 @@ xaccAccountInsertLot (Account *acc, GNCLot *lot)
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
static void
|
||||
xaccPreSplitMove (Split *split, gpointer dummy)
|
||||
xaccPreSplitMove (Split *split)
|
||||
{
|
||||
xaccTransBeginEdit (xaccSplitGetParent (split));
|
||||
}
|
||||
@ -2193,7 +2192,7 @@ xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
|
||||
|
||||
/* optimizations */
|
||||
from_priv = GET_PRIVATE(accfrom);
|
||||
if (!from_priv->splits || accfrom == accto)
|
||||
if (from_priv->splits.empty() || accfrom == accto)
|
||||
return;
|
||||
|
||||
/* check for book mix-up */
|
||||
@ -2203,7 +2202,7 @@ xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
|
||||
xaccAccountBeginEdit(accfrom);
|
||||
xaccAccountBeginEdit(accto);
|
||||
/* Begin editing both accounts and all transactions in accfrom. */
|
||||
g_list_foreach(from_priv->splits, (GFunc)xaccPreSplitMove, nullptr);
|
||||
std::for_each (from_priv->splits.begin(), from_priv->splits.end(), xaccPreSplitMove);
|
||||
|
||||
/* Concatenate accfrom's lists of splits and lots to accto's lists. */
|
||||
//to_priv->splits = g_list_concat(to_priv->splits, from_priv->splits);
|
||||
@ -2220,10 +2219,11 @@ xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
|
||||
* Convert each split's amount to accto's commodity.
|
||||
* Commit to editing each transaction.
|
||||
*/
|
||||
g_list_foreach(from_priv->splits, (GFunc)xaccPostSplitMove, (gpointer)accto);
|
||||
std::for_each (from_priv->splits.begin(), from_priv->splits.end(),
|
||||
[accto](Split *s){ xaccPostSplitMove (s, accto); });
|
||||
|
||||
/* Finally empty accfrom. */
|
||||
g_assert(from_priv->splits == nullptr);
|
||||
g_assert(from_priv->splits.empty());
|
||||
g_assert(from_priv->lots == nullptr);
|
||||
xaccAccountCommitEdit(accfrom);
|
||||
xaccAccountCommitEdit(accto);
|
||||
@ -2268,7 +2268,6 @@ xaccAccountRecomputeBalance (Account * acc)
|
||||
gnc_numeric noclosing_balance;
|
||||
gnc_numeric cleared_balance;
|
||||
gnc_numeric reconciled_balance;
|
||||
GList *lp;
|
||||
|
||||
if (nullptr == acc) return;
|
||||
|
||||
@ -2285,9 +2284,8 @@ xaccAccountRecomputeBalance (Account * acc)
|
||||
|
||||
PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
|
||||
priv->accountName, balance.num, balance.denom);
|
||||
for (lp = priv->splits; lp; lp = lp->next)
|
||||
for (auto split : priv->splits)
|
||||
{
|
||||
Split *split = (Split *) lp->data;
|
||||
gnc_numeric amt = xaccSplitGetAmount (split);
|
||||
|
||||
balance = gnc_numeric_add_fixed(balance, amt);
|
||||
@ -2607,7 +2605,6 @@ void
|
||||
xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
|
||||
{
|
||||
AccountPrivate *priv;
|
||||
GList *lp;
|
||||
|
||||
/* errors */
|
||||
g_return_if_fail(GNC_IS_ACCOUNT(acc));
|
||||
@ -2626,9 +2623,8 @@ xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
|
||||
priv->non_standard_scu = FALSE;
|
||||
|
||||
/* iterate over splits */
|
||||
for (lp = priv->splits; lp; lp = lp->next)
|
||||
for (auto s : priv->splits)
|
||||
{
|
||||
Split *s = (Split *) lp->data;
|
||||
Transaction *trans = xaccSplitGetParent (s);
|
||||
|
||||
xaccTransBeginEdit (trans);
|
||||
@ -3540,35 +3536,20 @@ xaccAccountGetReconciledBalance (const Account *acc)
|
||||
gnc_numeric
|
||||
xaccAccountGetProjectedMinimumBalance (const Account *acc)
|
||||
{
|
||||
AccountPrivate *priv;
|
||||
GList *node;
|
||||
time64 today;
|
||||
gnc_numeric lowest = gnc_numeric_zero ();
|
||||
int seen_a_transaction = 0;
|
||||
auto today{gnc_time64_get_today_end()};
|
||||
std::optional<gnc_numeric> minimum;
|
||||
|
||||
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
|
||||
|
||||
priv = GET_PRIVATE(acc);
|
||||
today = gnc_time64_get_today_end();
|
||||
for (node = g_list_last(priv->splits); node; node = node->prev)
|
||||
auto before_today_end = [&minimum, today](const Split *s) -> bool
|
||||
{
|
||||
Split *split = static_cast<Split*>(node->data);
|
||||
|
||||
if (!seen_a_transaction)
|
||||
{
|
||||
lowest = xaccSplitGetBalance (split);
|
||||
seen_a_transaction = 1;
|
||||
}
|
||||
else if (gnc_numeric_compare(xaccSplitGetBalance (split), lowest) < 0)
|
||||
{
|
||||
lowest = xaccSplitGetBalance (split);
|
||||
}
|
||||
|
||||
if (xaccTransGetDate (xaccSplitGetParent (split)) <= today)
|
||||
return lowest;
|
||||
}
|
||||
|
||||
return lowest;
|
||||
auto bal{xaccSplitGetBalance(s)};
|
||||
if (!minimum || gnc_numeric_compare (bal, *minimum) < 0)
|
||||
minimum = bal;
|
||||
return (xaccTransGetDate(xaccSplitGetParent(s)) < today);
|
||||
};
|
||||
// scan to find today's split, but we're really interested in the
|
||||
// minimum balance
|
||||
[[maybe_unused]] auto todays_split = gnc_account_find_split (acc, before_today_end, true);
|
||||
return minimum ? *minimum : gnc_numeric_zero();
|
||||
}
|
||||
|
||||
|
||||
@ -3578,27 +3559,16 @@ xaccAccountGetProjectedMinimumBalance (const Account *acc)
|
||||
static gnc_numeric
|
||||
GetBalanceAsOfDate (Account *acc, time64 date, std::function<gnc_numeric(Split*)> split_to_numeric)
|
||||
{
|
||||
/* Ideally this could use xaccAccountForEachSplit, but
|
||||
* it doesn't exist yet and I'm uncertain of exactly how
|
||||
* it would work at this time, since it differs from
|
||||
* xaccAccountForEachTransaction by using gpointer return
|
||||
* values rather than gints.
|
||||
*/
|
||||
Split *latest = nullptr;
|
||||
|
||||
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
|
||||
|
||||
xaccAccountSortSplits (acc, TRUE); /* just in case, normally a noop */
|
||||
xaccAccountRecomputeBalance (acc); /* just in case, normally a noop */
|
||||
|
||||
for (GList *lp = GET_PRIVATE(acc)->splits; lp; lp = lp->next)
|
||||
{
|
||||
if (xaccTransGetDate (xaccSplitGetParent ((Split *)lp->data)) >= date)
|
||||
break;
|
||||
latest = (Split *)lp->data;
|
||||
}
|
||||
auto is_before_date = [date](auto s) -> bool
|
||||
{ return xaccTransGetDate(xaccSplitGetParent(s)) < date; };
|
||||
|
||||
return latest ? split_to_numeric (latest) : gnc_numeric_zero();
|
||||
auto latest_split{gnc_account_find_split (acc, is_before_date, true)};
|
||||
return latest_split ? split_to_numeric (latest_split) : gnc_numeric_zero();
|
||||
}
|
||||
|
||||
gnc_numeric
|
||||
@ -3616,19 +3586,7 @@ xaccAccountGetNoclosingBalanceAsOfDate (Account *acc, time64 date)
|
||||
gnc_numeric
|
||||
xaccAccountGetReconciledBalanceAsOfDate (Account *acc, time64 date)
|
||||
{
|
||||
gnc_numeric balance = gnc_numeric_zero();
|
||||
|
||||
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
|
||||
|
||||
for (GList *node = GET_PRIVATE(acc)->splits; node; node = node->next)
|
||||
{
|
||||
Split *split = (Split*) node->data;
|
||||
if ((xaccSplitGetReconcile (split) == YREC) &&
|
||||
(xaccSplitGetDateReconciled (split) <= date))
|
||||
balance = gnc_numeric_add_fixed (balance, xaccSplitGetAmount (split));
|
||||
};
|
||||
|
||||
return balance;
|
||||
return GetBalanceAsOfDate (acc, date, xaccSplitGetReconciledBalance);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4021,36 +3979,32 @@ xaccAccountGetNoclosingBalanceChangeInCurrencyForPeriod (Account *acc, time64 t1
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
/* THIS API NEEDS TO CHANGE.
|
||||
*
|
||||
* This code exposes the internal structure of the account object to
|
||||
* external callers by returning the actual list used by the object.
|
||||
* It should instead return a copy of the split list that the caller
|
||||
* is required to free. That change would provide the freedom of
|
||||
* allowing the internal organization to change data structures if
|
||||
* necessary for whatever reason, while leaving the external API
|
||||
* unchanged. */
|
||||
/* XXX: violates the const'ness by forcing a sort before returning
|
||||
* the splitlist */
|
||||
const SplitsVec
|
||||
xaccAccountGetSplits (const Account *account)
|
||||
{
|
||||
return GNC_IS_ACCOUNT(account) ? GET_PRIVATE(account)->splits : SplitsVec{};
|
||||
}
|
||||
|
||||
SplitList *
|
||||
xaccAccountGetSplitList (const Account *acc)
|
||||
{
|
||||
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
|
||||
xaccAccountSortSplits((Account*)acc, FALSE); // normally a noop
|
||||
return GET_PRIVATE(acc)->splits;
|
||||
auto priv{GET_PRIVATE(acc)};
|
||||
return std::accumulate (priv->splits.rbegin(), priv->splits.rend(),
|
||||
static_cast<GList*>(nullptr), g_list_prepend);
|
||||
}
|
||||
|
||||
size_t
|
||||
xaccAccountGetSplitsSize (const Account *account)
|
||||
{
|
||||
return GNC_IS_ACCOUNT(account) ? g_list_length (GET_PRIVATE(account)->splits) : 0;
|
||||
return GNC_IS_ACCOUNT(account) ? GET_PRIVATE(account)->splits.size() : 0;
|
||||
}
|
||||
|
||||
gboolean gnc_account_and_descendants_empty (Account *acc)
|
||||
{
|
||||
g_return_val_if_fail (GNC_IS_ACCOUNT (acc), FALSE);
|
||||
auto priv = GET_PRIVATE (acc);
|
||||
if (priv->splits != nullptr) return FALSE;
|
||||
if (!priv->splits.empty()) return FALSE;
|
||||
for (auto *n = priv->children; n; n = n->next)
|
||||
{
|
||||
if (!gnc_account_and_descendants_empty (static_cast<Account*>(n->data)))
|
||||
@ -5377,51 +5331,12 @@ xaccAccountGetReconcileChildrenStatus(const Account *acc)
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
/* The caller of this function can get back one or both of the
|
||||
* matching split and transaction pointers, depending on whether
|
||||
* a valid pointer to the location to store those pointers is
|
||||
* passed.
|
||||
*/
|
||||
static void
|
||||
finder_help_function(const Account *acc, const char *description,
|
||||
Split **split, Transaction **trans )
|
||||
{
|
||||
AccountPrivate *priv;
|
||||
GList *slp;
|
||||
|
||||
/* First, make sure we set the data to nullptr BEFORE we start */
|
||||
if (split) *split = nullptr;
|
||||
if (trans) *trans = nullptr;
|
||||
|
||||
/* Then see if we have any work to do */
|
||||
if (acc == nullptr) return;
|
||||
|
||||
/* Why is this loop iterated backwards ?? Presumably because the split
|
||||
* list is in date order, and the most recent matches should be
|
||||
* returned!? */
|
||||
priv = GET_PRIVATE(acc);
|
||||
for (slp = g_list_last(priv->splits); slp; slp = slp->prev)
|
||||
{
|
||||
Split *lsplit = static_cast<Split*>(slp->data);
|
||||
Transaction *ltrans = xaccSplitGetParent(lsplit);
|
||||
|
||||
if (g_strcmp0 (description, xaccTransGetDescription (ltrans)) == 0)
|
||||
{
|
||||
if (split) *split = lsplit;
|
||||
if (trans) *trans = ltrans;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Split *
|
||||
xaccAccountFindSplitByDesc(const Account *acc, const char *description)
|
||||
{
|
||||
Split *split;
|
||||
|
||||
/* Get the split which has a transaction matching the description. */
|
||||
finder_help_function(acc, description, &split, nullptr);
|
||||
return split;
|
||||
auto has_description = [description](const Split* s) -> bool
|
||||
{ return !g_strcmp0 (description, xaccTransGetDescription (xaccSplitGetParent (s))); };
|
||||
return gnc_account_find_split (acc, has_description, true);
|
||||
}
|
||||
|
||||
/* This routine is for finding a matching transaction in an account by
|
||||
@ -5432,11 +5347,8 @@ xaccAccountFindSplitByDesc(const Account *acc, const char *description)
|
||||
Transaction *
|
||||
xaccAccountFindTransByDesc(const Account *acc, const char *description)
|
||||
{
|
||||
Transaction *trans;
|
||||
|
||||
/* Get the translation matching the description. */
|
||||
finder_help_function(acc, description, nullptr, &trans);
|
||||
return trans;
|
||||
auto split = xaccAccountFindSplitByDesc (acc, description);
|
||||
return split ? xaccSplitGetParent (split) : nullptr;
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
@ -5519,8 +5431,8 @@ gnc_account_merge_children (Account *parent)
|
||||
gnc_account_merge_children (acc_a);
|
||||
|
||||
/* consolidate transactions */
|
||||
while (priv_b->splits)
|
||||
xaccSplitSetAccount (static_cast <Split*> (priv_b->splits->data), acc_a);
|
||||
while (!priv_b->splits.empty())
|
||||
xaccSplitSetAccount (priv_b->splits.front(), acc_a);
|
||||
|
||||
/* move back one before removal. next iteration around the loop
|
||||
* will get the node after node_b */
|
||||
@ -5538,14 +5450,11 @@ gnc_account_merge_children (Account *parent)
|
||||
/* Transaction Traversal functions */
|
||||
|
||||
|
||||
void
|
||||
xaccSplitsBeginStagedTransactionTraversals (GList *splits)
|
||||
static void
|
||||
xaccSplitsBeginStagedTransactionTraversals (SplitsVec splits)
|
||||
{
|
||||
GList *lp;
|
||||
|
||||
for (lp = splits; lp; lp = lp->next)
|
||||
for (auto s : splits)
|
||||
{
|
||||
Split *s = static_cast <Split*> (lp->data);
|
||||
Transaction *trans = s->parent;
|
||||
|
||||
if (trans)
|
||||
@ -5557,12 +5466,9 @@ xaccSplitsBeginStagedTransactionTraversals (GList *splits)
|
||||
void
|
||||
xaccAccountBeginStagedTransactionTraversals (const Account *account)
|
||||
{
|
||||
AccountPrivate *priv;
|
||||
|
||||
if (!account)
|
||||
return;
|
||||
priv = GET_PRIVATE(account);
|
||||
xaccSplitsBeginStagedTransactionTraversals(priv->splits);
|
||||
xaccSplitsBeginStagedTransactionTraversals(GET_PRIVATE (account)->splits);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -5579,16 +5485,11 @@ xaccTransactionTraverse (Transaction *trans, int stage)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void do_one_split (Split *s, gpointer data)
|
||||
{
|
||||
Transaction *trans = s->parent;
|
||||
trans->marker = 0;
|
||||
}
|
||||
|
||||
static void do_one_account (Account *account, gpointer data)
|
||||
{
|
||||
AccountPrivate *priv = GET_PRIVATE(account);
|
||||
g_list_foreach(priv->splits, (GFunc)do_one_split, nullptr);
|
||||
std::for_each (priv->splits.begin(), priv->splits.end(),
|
||||
[](auto s){ s->parent->marker = 0; });
|
||||
}
|
||||
|
||||
/* Replacement for xaccGroupBeginStagedTransactionTraversals */
|
||||
@ -5608,32 +5509,18 @@ xaccAccountStagedTransactionTraversal (const Account *acc,
|
||||
TransactionCallback thunk,
|
||||
void *cb_data)
|
||||
{
|
||||
AccountPrivate *priv;
|
||||
GList *split_p;
|
||||
GList *next;
|
||||
Transaction *trans;
|
||||
Split *s;
|
||||
int retval;
|
||||
|
||||
if (!acc) return 0;
|
||||
|
||||
priv = GET_PRIVATE(acc);
|
||||
for (split_p = priv->splits; split_p; split_p = next)
|
||||
auto splits = GET_PRIVATE(acc)->splits;
|
||||
for (auto s : splits)
|
||||
{
|
||||
/* Get the next element in the split list now, just in case some
|
||||
* naughty thunk destroys the one we're using. This reduces, but
|
||||
* does not eliminate, the possibility of undefined results if
|
||||
* a thunk removes splits from this account. */
|
||||
next = g_list_next(split_p);
|
||||
|
||||
s = static_cast <Split*> (split_p->data);
|
||||
trans = s->parent;
|
||||
auto trans = s->parent;
|
||||
if (trans && (trans->marker < stage))
|
||||
{
|
||||
trans->marker = stage;
|
||||
if (thunk)
|
||||
{
|
||||
retval = thunk(trans, cb_data);
|
||||
auto retval = thunk(trans, cb_data);
|
||||
if (retval) return retval;
|
||||
}
|
||||
}
|
||||
@ -5649,16 +5536,14 @@ gnc_account_tree_staged_transaction_traversal (const Account *acc,
|
||||
void *cb_data)
|
||||
{
|
||||
const AccountPrivate *priv;
|
||||
GList *acc_p, *split_p;
|
||||
Transaction *trans;
|
||||
Split *s;
|
||||
int retval;
|
||||
|
||||
if (!acc) return 0;
|
||||
|
||||
/* depth first traversal */
|
||||
priv = GET_PRIVATE(acc);
|
||||
for (acc_p = priv->children; acc_p; acc_p = g_list_next(acc_p))
|
||||
for (auto acc_p = priv->children; acc_p; acc_p = g_list_next(acc_p))
|
||||
{
|
||||
retval = gnc_account_tree_staged_transaction_traversal(static_cast <Account*> (acc_p->data),
|
||||
stage, thunk, cb_data);
|
||||
@ -5666,9 +5551,8 @@ gnc_account_tree_staged_transaction_traversal (const Account *acc,
|
||||
}
|
||||
|
||||
/* Now this account */
|
||||
for (split_p = priv->splits; split_p; split_p = g_list_next(split_p))
|
||||
for (auto s : priv->splits)
|
||||
{
|
||||
s = static_cast <Split*> (split_p->data);
|
||||
trans = s->parent;
|
||||
if (trans && (trans->marker < stage))
|
||||
{
|
||||
|
@ -1493,12 +1493,6 @@ typedef enum
|
||||
*/
|
||||
void gnc_account_tree_begin_staged_transaction_traversals(Account *acc);
|
||||
|
||||
/** xaccSplitsBeginStagedTransactionTraversals() resets the traversal
|
||||
* marker for each transaction which is a parent of one of the
|
||||
* splits in the list.
|
||||
*/
|
||||
void xaccSplitsBeginStagedTransactionTraversals(SplitList *splits);
|
||||
|
||||
/** xaccAccountBeginStagedTransactionTraversals() resets the traversal
|
||||
* marker for each transaction which is a parent of one of the
|
||||
* splits in the account.
|
||||
|
58
libgnucash/engine/Account.hpp
Normal file
58
libgnucash/engine/Account.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
/**********************************************************************
|
||||
* Account.hpp
|
||||
* *
|
||||
* 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@gnu.org *
|
||||
* *
|
||||
*********************************************************************/
|
||||
|
||||
/** @addtogroup Engine
|
||||
@{ */
|
||||
/** @addtogroup Account
|
||||
|
||||
@{ */
|
||||
/** @file Account.hpp
|
||||
* @brief Account public routines (C++ api)
|
||||
*/
|
||||
|
||||
#ifndef GNC_ACCOUNT_HPP
|
||||
#define GNC_ACCOUNT_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include <Account.h>
|
||||
|
||||
using SplitsVec = std::vector<Split*>;
|
||||
|
||||
const SplitsVec xaccAccountGetSplits (const Account*);
|
||||
|
||||
/** scans account split list (in forward or reverse order) until
|
||||
* predicate split->bool returns true. Maybe return the split.
|
||||
*
|
||||
* @param acc The account to which the split should be added.
|
||||
*
|
||||
* @param predicate A split->bool predicate.
|
||||
*
|
||||
* @param reverse To scan in reverse order
|
||||
*
|
||||
* @result Split* or nullptr if not found */
|
||||
Split* gnc_account_find_split (const Account*, std::function<bool(const Split*)>, bool);
|
||||
|
||||
#endif /* GNC_COMMODITY_HPP */
|
||||
/** @} */
|
||||
/** @} */
|
@ -39,6 +39,7 @@
|
||||
#ifndef XACC_ACCOUNT_P_H
|
||||
#define XACC_ACCOUNT_P_H
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include "Account.h"
|
||||
@ -118,7 +119,7 @@ typedef struct AccountPrivate
|
||||
|
||||
gboolean balance_dirty; /* balances in splits incorrect */
|
||||
|
||||
GList *splits; /* list of split pointers */
|
||||
std::vector<Split*> splits; /* list of split pointers */
|
||||
gboolean sort_dirty; /* sort order of splits is bad */
|
||||
|
||||
LotList *lots; /* list of lot pointers */
|
||||
|
@ -31,6 +31,7 @@ set(engine_noinst_HEADERS
|
||||
)
|
||||
|
||||
set (engine_HEADERS
|
||||
Account.hpp
|
||||
Account.h
|
||||
FreqSpec.h
|
||||
Recurrence.h
|
||||
|
@ -385,6 +385,7 @@ gnc_sx_get_sxes_referencing_account(QofBook *book, Account *acct)
|
||||
|
||||
guid_free (guid);
|
||||
}
|
||||
g_list_free (splits);
|
||||
}
|
||||
return g_list_reverse (rtn);
|
||||
}
|
||||
|
@ -454,6 +454,7 @@ delete_template_trans(SchedXaction *sx)
|
||||
sxprivTransMapDelete,
|
||||
NULL);
|
||||
|
||||
g_list_free (templ_acct_splits);
|
||||
g_list_free (templ_acct_transactions);
|
||||
return;
|
||||
}
|
||||
|
@ -217,6 +217,7 @@ gint gnc_sx_get_instance_count( const SchedXaction *sx, /*@ null @*/ SXTmpStateD
|
||||
*/
|
||||
void gnc_sx_set_instance_count( SchedXaction *sx, gint instanceNum );
|
||||
|
||||
/* must be g_list_freed */
|
||||
GList *xaccSchedXactionGetSplits( const SchedXaction *sx );
|
||||
void xaccSchedXactionSetSplits( SchedXaction *sx, GList *newSplits );
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
|
||||
#include "Account.h"
|
||||
#include "AccountP.hpp"
|
||||
#include "Account.hpp"
|
||||
#include "Scrub.h"
|
||||
#include "Transaction.h"
|
||||
#include "TransactionP.h"
|
||||
@ -91,8 +92,8 @@ gnc_get_ongoing_scrub (void)
|
||||
|
||||
static void add_transactions (const Account *account, GHashTable **ht)
|
||||
{
|
||||
for (GList *m = xaccAccountGetSplitList (account); m; m = g_list_next (m))
|
||||
g_hash_table_add (*ht, xaccSplitGetParent (GNC_SPLIT(m->data)));
|
||||
for (auto s : xaccAccountGetSplits (account))
|
||||
g_hash_table_add (*ht, xaccSplitGetParent (s));
|
||||
}
|
||||
|
||||
static GList*
|
||||
@ -226,12 +227,11 @@ xaccAccountTreeScrubSplits (Account *account)
|
||||
void
|
||||
xaccAccountScrubSplits (Account *account)
|
||||
{
|
||||
GList *node;
|
||||
scrub_depth++;
|
||||
for (node = xaccAccountGetSplitList (account); node; node = node->next)
|
||||
for (auto s : xaccAccountGetSplits (account))
|
||||
{
|
||||
if (abort_now) break;
|
||||
xaccSplitScrub (GNC_SPLIT(node->data));
|
||||
xaccSplitScrub (s);
|
||||
}
|
||||
scrub_depth--;
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "qof.h"
|
||||
#include "Account.h"
|
||||
#include "AccountP.hpp"
|
||||
#include "Account.hpp"
|
||||
#include "Transaction.h"
|
||||
#include "TransactionP.h"
|
||||
#include "Scrub2.h"
|
||||
@ -57,19 +58,14 @@ static QofLogModule log_module = GNC_MOD_LOT;
|
||||
void
|
||||
xaccAccountAssignLots (Account *acc)
|
||||
{
|
||||
SplitList *splits, *node;
|
||||
|
||||
if (!acc) return;
|
||||
|
||||
ENTER ("acc=%s", xaccAccountGetName(acc));
|
||||
xaccAccountBeginEdit (acc);
|
||||
|
||||
restart_loop:
|
||||
splits = xaccAccountGetSplitList(acc);
|
||||
for (node = splits; node; node = node->next)
|
||||
for (auto split : xaccAccountGetSplits (acc))
|
||||
{
|
||||
Split * split = GNC_SPLIT(node->data);
|
||||
|
||||
/* If already in lot, then no-op */
|
||||
if (split->lot) continue;
|
||||
|
||||
|
@ -410,6 +410,7 @@ gncScrubLotDanglingPayments (GNCLot *lot)
|
||||
|
||||
filtered_list = g_list_prepend (filtered_list, free_split);
|
||||
}
|
||||
g_list_free (split_list);
|
||||
|
||||
filtered_list = g_list_reverse (filtered_list);
|
||||
match_list = gncSLFindOffsSplits (filtered_list, ll_val);
|
||||
@ -695,7 +696,7 @@ gncScrubBusinessAccountSplits (Account *acc, QofPercentageFunc percentagefunc)
|
||||
restart:
|
||||
curr_split_no = 0;
|
||||
splits = xaccAccountGetSplitList(acc);
|
||||
split_count = g_list_length (splits);
|
||||
split_count = xaccAccountGetSplitsSize (acc);
|
||||
for (node = splits; node; node = node->next)
|
||||
{
|
||||
Split *split = node->data;
|
||||
@ -723,6 +724,7 @@ restart:
|
||||
curr_split_no + 1, split_count);
|
||||
curr_split_no++;
|
||||
}
|
||||
g_list_free (splits);
|
||||
xaccAccountCommitEdit(acc);
|
||||
(percentagefunc)(NULL, -1.0);
|
||||
LEAVE ("(acc=%s)", str);
|
||||
|
@ -58,6 +58,7 @@ ToDo:
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "Account.hpp"
|
||||
#include "AccountP.hpp"
|
||||
#include "Scrub2.h"
|
||||
#include "Scrub3.h"
|
||||
@ -79,7 +80,6 @@ gboolean
|
||||
xaccAccountHasTrades (const Account *acc)
|
||||
{
|
||||
gnc_commodity *acc_comm;
|
||||
SplitList *splits, *node;
|
||||
|
||||
if (!acc) return FALSE;
|
||||
|
||||
@ -88,10 +88,8 @@ xaccAccountHasTrades (const Account *acc)
|
||||
|
||||
acc_comm = xaccAccountGetCommodity(acc);
|
||||
|
||||
splits = xaccAccountGetSplitList(acc);
|
||||
for (node = splits; node; node = node->next)
|
||||
for (auto s : xaccAccountGetSplits (acc))
|
||||
{
|
||||
Split *s = GNC_SPLIT(node->data);
|
||||
Transaction *t = s->parent;
|
||||
if (s->gains == GAINS_STATUS_GAINS) continue;
|
||||
if (acc_comm != t->common_currency) return TRUE;
|
||||
|
@ -76,6 +76,16 @@ xaccAccountGetSplitList (const Account *account)
|
||||
return mockaccount ? mockaccount->xaccAccountGetSplitList() : nullptr;
|
||||
}
|
||||
|
||||
const std::vector<Split*>
|
||||
xaccAccountGetSplits (const Account *account)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
auto mockaccount = gnc_mockaccount(account);
|
||||
if (!mockaccount)
|
||||
return {};
|
||||
return mockaccount->xaccAccountGetSplits();
|
||||
}
|
||||
|
||||
|
||||
Account*
|
||||
gnc_account_imap_find_account (
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <Account.h>
|
||||
#include <Account.hpp>
|
||||
#include <AccountP.hpp>
|
||||
#include <qofbook.h>
|
||||
|
||||
@ -45,6 +46,7 @@ public:
|
||||
MOCK_CONST_METHOD0(get_commodity, gnc_commodity*());
|
||||
MOCK_CONST_METHOD2(for_each_transaction, gint(TransactionCallback, void*));
|
||||
MOCK_CONST_METHOD0(xaccAccountGetSplitList, SplitList*());
|
||||
MOCK_CONST_METHOD0(xaccAccountGetSplits, std::vector<Split*>());
|
||||
MOCK_METHOD2(find_account, Account *(const char*, const char*));
|
||||
MOCK_METHOD3(add_account, void(const char*, const char*, Account*));
|
||||
MOCK_METHOD1(find_account_bayes, Account *(std::vector<const char*>&));
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include "Account.h"
|
||||
#include "Account.hpp"
|
||||
#include "Transaction.h"
|
||||
#include "TransactionP.h"
|
||||
#include "cap-gains.h"
|
||||
@ -100,38 +101,16 @@ DirectionPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot, short reverse)
|
||||
* hasn't been assigned to a lot. Return that split.
|
||||
* Make use of the fact that the splits in an account are
|
||||
* already in date order; so we don't have to sort. */
|
||||
auto splits = xaccAccountGetSplitList (lot_account);
|
||||
|
||||
Split *rv = nullptr;
|
||||
|
||||
for (auto node = reverse ? g_list_last (splits) : splits; !rv && node;
|
||||
node = reverse ? node->prev : node->next)
|
||||
auto find_split = [open_time, common_currency, want_positive](const Split* split)
|
||||
{
|
||||
split = GNC_SPLIT(node->data);
|
||||
if (split->lot)
|
||||
continue;
|
||||
return (!split->lot &&
|
||||
xaccTransRetDatePosted (xaccSplitGetParent (split)) >= open_time &&
|
||||
gnc_commodity_equiv (common_currency, split->parent->common_currency) &&
|
||||
!gnc_numeric_zero_p (split->amount) &&
|
||||
want_positive == gnc_numeric_positive_p (split->amount));
|
||||
};
|
||||
|
||||
/* Skip it if it's too early */
|
||||
if (xaccTransRetDatePosted (xaccSplitGetParent (split)) < open_time)
|
||||
{
|
||||
if (reverse)
|
||||
/* Going backwards, no point in looking further */
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Allow equiv currencies */
|
||||
if (!gnc_commodity_equiv (common_currency, split->parent->common_currency))
|
||||
continue;
|
||||
|
||||
/* Disallow zero-amount splits in general. */
|
||||
if (gnc_numeric_zero_p(split->amount))
|
||||
continue;
|
||||
|
||||
if (want_positive == gnc_numeric_positive_p (split->amount))
|
||||
rv = split;
|
||||
}
|
||||
return rv;
|
||||
return gnc_account_find_split (lot_account, find_split, reverse);
|
||||
}
|
||||
|
||||
/* ============================================================== */
|
||||
|
@ -1074,7 +1074,6 @@ make_random_changes_to_level (QofBook *book, Account *parent)
|
||||
account = static_cast<Account*>(get_random_list_element (accounts));
|
||||
|
||||
splits = xaccAccountGetSplitList (account);
|
||||
splits = g_list_copy (splits);
|
||||
|
||||
for (node = splits; node; node = node->next)
|
||||
{
|
||||
|
@ -882,7 +882,7 @@ test_xaccFreeAccount (Fixture *fixture, gconstpointer pData)
|
||||
/* Check that we've got children, lots, and splits to remove */
|
||||
g_assert_true (p_priv->children != NULL);
|
||||
g_assert_true (p_priv->lots != NULL);
|
||||
g_assert_true (p_priv->splits != NULL);
|
||||
g_assert_true (p_priv->splits.size());
|
||||
g_assert_true (p_priv->parent != NULL);
|
||||
g_assert_true (p_priv->commodity != NULL);
|
||||
g_assert_cmpint (check1->hits, ==, 0);
|
||||
@ -983,7 +983,7 @@ test_xaccAccountCommitEdit (Fixture *fixture, gconstpointer pData)
|
||||
/* Check that we've got children, lots, and splits to remove */
|
||||
g_assert_true (p_priv->children != NULL);
|
||||
g_assert_true (p_priv->lots != NULL);
|
||||
g_assert_true (p_priv->splits != NULL);
|
||||
g_assert_true (p_priv->splits.size());
|
||||
g_assert_true (p_priv->parent != NULL);
|
||||
g_assert_true (p_priv->commodity != NULL);
|
||||
g_assert_cmpint (check1->hits, ==, 0);
|
||||
@ -998,7 +998,7 @@ test_xaccAccountCommitEdit (Fixture *fixture, gconstpointer pData)
|
||||
test_signal_assert_hits (sig2, 0);
|
||||
g_assert_true (p_priv->children != NULL);
|
||||
g_assert_true (p_priv->lots != NULL);
|
||||
g_assert_true (p_priv->splits != NULL);
|
||||
g_assert_true (p_priv->splits.size());
|
||||
g_assert_true (p_priv->parent != NULL);
|
||||
g_assert_true (p_priv->commodity != NULL);
|
||||
g_assert_cmpint (check1->hits, ==, 0);
|
||||
@ -1393,19 +1393,19 @@ test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
|
||||
|
||||
/* Check that the call fails with invalid account and split (throws) */
|
||||
g_assert_true (!gnc_account_insert_split (NULL, split1));
|
||||
g_assert_cmpuint (g_list_length (priv->splits), == , 0);
|
||||
g_assert_cmpuint (priv->splits.size(), == , 0);
|
||||
g_assert_true (!priv->sort_dirty);
|
||||
g_assert_true (!priv->balance_dirty);
|
||||
test_signal_assert_hits (sig1, 0);
|
||||
test_signal_assert_hits (sig2, 0);
|
||||
g_assert_true (!gnc_account_insert_split (fixture->acct, NULL));
|
||||
g_assert_cmpuint (g_list_length (priv->splits), == , 0);
|
||||
g_assert_cmpuint (priv->splits.size(), == , 0);
|
||||
g_assert_true (!priv->sort_dirty);
|
||||
g_assert_true (!priv->balance_dirty);
|
||||
test_signal_assert_hits (sig1, 0);
|
||||
test_signal_assert_hits (sig2, 0);
|
||||
/* g_assert_true (!gnc_account_insert_split (fixture->acct, (Split*)priv)); */
|
||||
/* g_assert_cmpuint (g_list_length (priv->splits), == , 0); */
|
||||
/* g_assert_cmpuint (priv->splits.size(), == , 0); */
|
||||
/* g_assert_true (!priv->sort_dirty); */
|
||||
/* g_assert_true (!priv->balance_dirty); */
|
||||
/* test_signal_assert_hits (sig1, 0); */
|
||||
@ -1418,7 +1418,7 @@ test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
|
||||
|
||||
/* Check that it works the first time */
|
||||
g_assert_true (gnc_account_insert_split (fixture->acct, split1));
|
||||
g_assert_cmpuint (g_list_length (priv->splits), == , 1);
|
||||
g_assert_cmpuint (priv->splits.size(), == , 1);
|
||||
g_assert_true (!priv->sort_dirty);
|
||||
g_assert_true (priv->balance_dirty);
|
||||
test_signal_assert_hits (sig1, 1);
|
||||
@ -1430,7 +1430,7 @@ test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
|
||||
sig3 = test_signal_new (&fixture->acct->inst, GNC_EVENT_ITEM_ADDED, split2);
|
||||
/* Now add a second split to the account and check that sort_dirty isn't set. We have to bump the editlevel to force this. */
|
||||
g_assert_true (gnc_account_insert_split (fixture->acct, split2));
|
||||
g_assert_cmpuint (g_list_length (priv->splits), == , 2);
|
||||
g_assert_cmpuint (priv->splits.size(), == , 2);
|
||||
g_assert_true (!priv->sort_dirty);
|
||||
g_assert_true (priv->balance_dirty);
|
||||
test_signal_assert_hits (sig1, 2);
|
||||
@ -1441,7 +1441,7 @@ test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
|
||||
qof_instance_increase_editlevel (fixture->acct);
|
||||
g_assert_true (gnc_account_insert_split (fixture->acct, split3));
|
||||
qof_instance_decrease_editlevel (fixture->acct);
|
||||
g_assert_cmpuint (g_list_length (priv->splits), == , 3);
|
||||
g_assert_cmpuint (priv->splits.size(), == , 3);
|
||||
g_assert_true (priv->sort_dirty);
|
||||
g_assert_true (priv->balance_dirty);
|
||||
test_signal_assert_hits (sig1, 3);
|
||||
@ -1452,7 +1452,7 @@ test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
|
||||
sig3 = test_signal_new (&fixture->acct->inst, GNC_EVENT_ITEM_REMOVED,
|
||||
split3);
|
||||
g_assert_true (gnc_account_remove_split (fixture->acct, split3));
|
||||
g_assert_cmpuint (g_list_length (priv->splits), == , 2);
|
||||
g_assert_cmpuint (priv->splits.size(), == , 2);
|
||||
g_assert_true (priv->sort_dirty);
|
||||
g_assert_true (!priv->balance_dirty);
|
||||
test_signal_assert_hits (sig1, 4);
|
||||
@ -1460,7 +1460,7 @@ test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
|
||||
/* And do it again to make sure that it fails when the split has
|
||||
* already been removed */
|
||||
g_assert_true (!gnc_account_remove_split (fixture->acct, split3));
|
||||
g_assert_cmpuint (g_list_length (priv->splits), == , 2);
|
||||
g_assert_cmpuint (priv->splits.size(), == , 2);
|
||||
g_assert_true (priv->sort_dirty);
|
||||
g_assert_true (!priv->balance_dirty);
|
||||
test_signal_assert_hits (sig1, 4);
|
||||
|
@ -329,8 +329,7 @@ test_invoice_doclink ( Fixture *fixture, gconstpointer pData )
|
||||
|
||||
static gboolean account_has_one_split (const Account *acc)
|
||||
{
|
||||
GList *splits = xaccAccountGetSplitList (acc);
|
||||
return (splits && !(splits->next));
|
||||
return (xaccAccountGetSplitsSize (acc) == 1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user