LCOV - code coverage report
Current view: top level - libgnucash/engine - Scrub.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 46.8 % 673 315
Test Date: 2025-02-07 16:25:45 Functions: 51.9 % 52 27
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************\
       2                 :             :  * Scrub.c -- convert single-entry accounts into clean double-entry *
       3                 :             :  *                                                                  *
       4                 :             :  * This program is free software; you can redistribute it and/or    *
       5                 :             :  * modify it under the terms of the GNU General Public License as   *
       6                 :             :  * published by the Free Software Foundation; either version 2 of   *
       7                 :             :  * the License, or (at your option) any later version.              *
       8                 :             :  *                                                                  *
       9                 :             :  * This program is distributed in the hope that it will be useful,  *
      10                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      11                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      12                 :             :  * GNU General Public License for more details.                     *
      13                 :             :  *                                                                  *
      14                 :             :  * You should have received a copy of the GNU General Public License*
      15                 :             :  * along with this program; if not, contact:                        *
      16                 :             :  *                                                                  *
      17                 :             :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      18                 :             :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      19                 :             :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      20                 :             :  *                                                                  *
      21                 :             : \********************************************************************/
      22                 :             : 
      23                 :             : /*
      24                 :             :  * FILE:
      25                 :             :  * Scrub.c
      26                 :             :  *
      27                 :             :  * FUNCTION:
      28                 :             :  * Provides a set of functions and utilities for scrubbing clean
      29                 :             :  * single-entry accounts so that they can be promoted into
      30                 :             :  * self-consistent, clean double-entry accounts.
      31                 :             :  *
      32                 :             :  * HISTORY:
      33                 :             :  * Created by Linas Vepstas December 1998
      34                 :             :  * Copyright (c) 1998-2000, 2003 Linas Vepstas <linas@linas.org>
      35                 :             :  * Copyright (c) 2002 Christian Stimming
      36                 :             :  * Copyright (c) 2006 David Hampton
      37                 :             :  */
      38                 :             : 
      39                 :             : #include <config.h>
      40                 :             : 
      41                 :             : #include <glib.h>
      42                 :             : #include <glib/gi18n.h>
      43                 :             : #include <stdio.h>
      44                 :             : #include <string.h>
      45                 :             : #include <stdint.h>
      46                 :             : #include <stdbool.h>
      47                 :             : #include <unordered_set>
      48                 :             : 
      49                 :             : #include "Account.h"
      50                 :             : #include "AccountP.hpp"
      51                 :             : #include "Account.hpp"
      52                 :             : #include "Scrub.h"
      53                 :             : #include "Transaction.h"
      54                 :             : #include "TransactionP.hpp"
      55                 :             : #include "gnc-commodity.h"
      56                 :             : #include "qofinstance-p.h"
      57                 :             : #include "gnc-session.h"
      58                 :             : 
      59                 :             : #undef G_LOG_DOMAIN
      60                 :             : #define G_LOG_DOMAIN "gnc.engine.scrub"
      61                 :             : 
      62                 :             : static QofLogModule log_module = G_LOG_DOMAIN;
      63                 :             : static gboolean abort_now = FALSE;
      64                 :             : static gint scrub_depth = 0;
      65                 :             : 
      66                 :             : 
      67                 :             : static Account* xaccScrubUtilityGetOrMakeAccount (Account *root,
      68                 :             :                                                   gnc_commodity* currency,
      69                 :             :                                                   const char* accname,
      70                 :             :                                                   GNCAccountType acctype,
      71                 :             :                                                   gboolean placeholder,
      72                 :             :                                                   gboolean checkname);
      73                 :             : 
      74                 :             : void
      75                 :           0 : gnc_set_abort_scrub (gboolean abort)
      76                 :             : {
      77                 :           0 :     abort_now = abort;
      78                 :           0 : }
      79                 :             : 
      80                 :             : gboolean
      81                 :           0 : gnc_get_abort_scrub (void)
      82                 :             : {
      83                 :           0 :     return abort_now;
      84                 :             : }
      85                 :             : 
      86                 :             : gboolean
      87                 :           0 : gnc_get_ongoing_scrub (void)
      88                 :             : {
      89                 :           0 :     return scrub_depth > 0;
      90                 :             : }
      91                 :             : 
      92                 :             : /* ================================================================ */
      93                 :             : 
      94                 :             : using TransSet = std::unordered_set<Transaction*>;
      95                 :             : 
      96                 :             : static TransSet
      97                 :           0 : get_all_transactions (Account *account, bool descendants)
      98                 :             : {
      99                 :           0 :     TransSet set;
     100                 :           0 :     auto add_transactions = [&set](auto a)
     101                 :           0 :     { gnc_account_foreach_split (a, [&set](auto s){ set.insert (xaccSplitGetParent (s)); }, false); };
     102                 :           0 :     add_transactions (account);
     103                 :           0 :     if (descendants)
     104                 :           0 :         gnc_account_foreach_descendant (account, add_transactions);
     105                 :           0 :     return set;
     106                 :           0 : }
     107                 :             : 
     108                 :             : /* ================================================================ */
     109                 :             : 
     110                 :             : static void
     111                 :        1612 : TransScrubOrphansFast (Transaction *trans, Account *root)
     112                 :             : {
     113                 :        1612 :     g_return_if_fail (trans && trans->common_currency && root);
     114                 :             : 
     115                 :        4868 :     for (GList *node = trans->splits; node; node = node->next)
     116                 :             :     {
     117                 :        3272 :         Split *split = GNC_SPLIT(node->data);
     118                 :        3272 :         if (abort_now) break;
     119                 :             : 
     120                 :        3272 :         if (split->acc) continue;
     121                 :             : 
     122                 :          57 :         DEBUG ("Found an orphan\n");
     123                 :             : 
     124                 :             :         gchar *accname = g_strconcat
     125                 :          57 :             (_("Orphan"), "-", gnc_commodity_get_mnemonic (trans->common_currency),
     126                 :             :              nullptr);
     127                 :             : 
     128                 :             :         Account *orph = xaccScrubUtilityGetOrMakeAccount
     129                 :          57 :             (root, trans->common_currency, accname, ACCT_TYPE_BANK, false, true);
     130                 :             : 
     131                 :          57 :         g_free (accname);
     132                 :          57 :         if (!orph) continue;
     133                 :             : 
     134                 :          57 :         xaccSplitSetAccount(split, orph);
     135                 :             :     }
     136                 :             : }
     137                 :             : 
     138                 :             : static void
     139                 :           0 : AccountScrubOrphans (Account *acc, bool descendants, QofPercentageFunc percentagefunc)
     140                 :             : {
     141                 :           0 :     if (!acc) return;
     142                 :           0 :     scrub_depth++;
     143                 :             : 
     144                 :           0 :     auto transactions = get_all_transactions (acc, descendants);
     145                 :           0 :     auto total_trans = transactions.size();
     146                 :           0 :     const char *message = _("Looking for orphans in transaction: %u of %zu");
     147                 :           0 :     guint current_trans = 0;
     148                 :             : 
     149                 :           0 :     for (auto trans : transactions)
     150                 :             :     {
     151                 :           0 :         if (current_trans % 10 == 0)
     152                 :             :         {
     153                 :           0 :             char *progress_msg = g_strdup_printf (message, current_trans, total_trans);
     154                 :           0 :             (percentagefunc)(progress_msg, (100 * current_trans) / total_trans);
     155                 :           0 :             g_free (progress_msg);
     156                 :           0 :             if (abort_now) break;
     157                 :             :         }
     158                 :             : 
     159                 :           0 :         TransScrubOrphansFast (trans, gnc_account_get_root (acc));
     160                 :           0 :         current_trans++;
     161                 :             :     }
     162                 :           0 :     (percentagefunc)(nullptr, -1.0);
     163                 :           0 :     scrub_depth--;
     164                 :           0 : }
     165                 :             : 
     166                 :             : void
     167                 :           0 : xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
     168                 :             : {
     169                 :           0 :     AccountScrubOrphans (acc, false, percentagefunc);
     170                 :           0 : }
     171                 :             : 
     172                 :             : void
     173                 :           0 : xaccAccountTreeScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
     174                 :             : {
     175                 :           0 :     AccountScrubOrphans (acc, true, percentagefunc);
     176                 :           0 : }
     177                 :             : 
     178                 :             : void
     179                 :        1612 : xaccTransScrubOrphans (Transaction *trans)
     180                 :             : {
     181                 :             :     SplitList *node;
     182                 :        1612 :     QofBook *book = nullptr;
     183                 :        1612 :     Account *root = nullptr;
     184                 :             : 
     185                 :        1612 :     if (!trans) return;
     186                 :             : 
     187                 :        1680 :     for (node = trans->splits; node; node = node->next)
     188                 :             :     {
     189                 :        1616 :         Split *split = GNC_SPLIT(node->data);
     190                 :        1616 :         if (abort_now) break;
     191                 :             : 
     192                 :        1616 :         if (split->acc)
     193                 :             :         {
     194                 :        1548 :             TransScrubOrphansFast (trans, gnc_account_get_root(split->acc));
     195                 :        1548 :             return;
     196                 :             :         }
     197                 :             :     }
     198                 :             : 
     199                 :             :     /* If we got to here, then *none* of the splits belonged to an
     200                 :             :      * account.  Not a happy situation.  We should dig an account
     201                 :             :      * out of the book the transaction belongs to.
     202                 :             :      * XXX we should probably *always* to this, instead of the above loop!
     203                 :             :      */
     204                 :          64 :     PINFO ("Free Floating Transaction!");
     205                 :          64 :     book = xaccTransGetBook (trans);
     206                 :          64 :     root = gnc_book_get_root_account (book);
     207                 :          64 :     TransScrubOrphansFast (trans, root);
     208                 :             : }
     209                 :             : 
     210                 :             : /* ================================================================ */
     211                 :             : 
     212                 :             : void
     213                 :          21 : xaccAccountTreeScrubSplits (Account *account)
     214                 :             : {
     215                 :          21 :     if (!account) return;
     216                 :             : 
     217                 :          21 :     xaccAccountScrubSplits (account);
     218                 :          21 :     gnc_account_foreach_descendant(account,
     219                 :             :                                    (AccountCb)xaccAccountScrubSplits, nullptr);
     220                 :             : }
     221                 :             : 
     222                 :             : void
     223                 :         451 : xaccAccountScrubSplits (Account *account)
     224                 :             : {
     225                 :         451 :     scrub_depth++;
     226                 :        2049 :     for (auto s : xaccAccountGetSplits (account))
     227                 :             :     {
     228                 :        1598 :         if (abort_now) break;
     229                 :        1598 :         xaccSplitScrub (s);
     230                 :             :     }
     231                 :         451 :     scrub_depth--;
     232                 :         451 : }
     233                 :             : 
     234                 :             : /* if dry_run is true, this function will analyze the split and
     235                 :             :    return true if the split will be modified during the actual scrub. */
     236                 :             : static bool
     237                 :        8240 : split_scrub_or_dry_run (Split *split, bool dry_run)
     238                 :             : {
     239                 :             :     Account *account;
     240                 :             :     Transaction *trans;
     241                 :             :     gnc_numeric value, amount;
     242                 :             :     gnc_commodity *currency, *acc_commodity;
     243                 :             :     int scu;
     244                 :             : 
     245                 :        8240 :     if (!split) return false;
     246                 :        8240 :     ENTER ("(split=%p)", split);
     247                 :             : 
     248                 :        8240 :     trans = xaccSplitGetParent (split);
     249                 :        8240 :     if (!trans)
     250                 :             :     {
     251                 :           8 :         LEAVE("no trans");
     252                 :           8 :         return false;
     253                 :             :     }
     254                 :             : 
     255                 :        8232 :     account = xaccSplitGetAccount (split);
     256                 :             : 
     257                 :             :     /* If there's no account, this split is an orphan.
     258                 :             :      * We need to fix that first, before proceeding.
     259                 :             :      */
     260                 :        8232 :     if (!account)
     261                 :             :     {
     262                 :         142 :         if (dry_run)
     263                 :          71 :             return true;
     264                 :             :         else
     265                 :          71 :             xaccTransScrubOrphans (trans);
     266                 :          71 :         account = xaccSplitGetAccount (split);
     267                 :             :     }
     268                 :             : 
     269                 :             :     /* Grrr... the register gnc_split_register_load() line 203 of
     270                 :             :      *  src/register/ledger-core/split-register-load.c will create
     271                 :             :      * free-floating bogus transactions. Ignore these for now ...
     272                 :             :      */
     273                 :        8161 :     if (!account)
     274                 :             :     {
     275                 :          16 :         PINFO ("Free Floating Transaction!");
     276                 :          16 :         LEAVE ("no account");
     277                 :          16 :         return false;
     278                 :             :     }
     279                 :             : 
     280                 :             :     /* Split amounts and values should be valid numbers */
     281                 :        8145 :     value = xaccSplitGetValue (split);
     282                 :        8145 :     if (gnc_numeric_check (value))
     283                 :             :     {
     284                 :           0 :         value = gnc_numeric_zero();
     285                 :           0 :         if (dry_run)
     286                 :           0 :             return true;
     287                 :             :         else
     288                 :           0 :             xaccSplitSetValue (split, value);
     289                 :             :     }
     290                 :             : 
     291                 :        8145 :     amount = xaccSplitGetAmount (split);
     292                 :        8145 :     if (gnc_numeric_check (amount))
     293                 :             :     {
     294                 :           0 :         amount = gnc_numeric_zero();
     295                 :           0 :         if (dry_run)
     296                 :           0 :             return true;
     297                 :             :         else
     298                 :           0 :             xaccSplitSetAmount (split, amount);
     299                 :             :     }
     300                 :             : 
     301                 :        8145 :     currency = xaccTransGetCurrency (trans);
     302                 :             : 
     303                 :             :     /* If the account doesn't have a commodity,
     304                 :             :      * we should attempt to fix that first.
     305                 :             :      */
     306                 :        8145 :     acc_commodity = xaccAccountGetCommodity(account);
     307                 :        8145 :     if (!acc_commodity)
     308                 :             :     {
     309                 :        1362 :         if (dry_run)
     310                 :         454 :             return true;
     311                 :             :         else
     312                 :         908 :             xaccAccountScrubCommodity (account);
     313                 :             :     }
     314                 :        7691 :     if (!acc_commodity || !gnc_commodity_equiv(acc_commodity, currency))
     315                 :             :     {
     316                 :        2740 :         LEAVE ("(split=%p) inequiv currency", split);
     317                 :        2740 :         return false;
     318                 :             :     }
     319                 :             : 
     320                 :        4951 :     scu = MIN (xaccAccountGetCommoditySCU (account),
     321                 :             :                gnc_commodity_get_fraction (currency));
     322                 :             : 
     323                 :        4951 :     if (gnc_numeric_same (amount, value, scu, GNC_HOW_RND_ROUND_HALF_UP))
     324                 :             :     {
     325                 :        4884 :         LEAVE("(split=%p) different values", split);
     326                 :        4884 :         return false;
     327                 :             :     }
     328                 :             : 
     329                 :          67 :     if (dry_run)
     330                 :          30 :         return true;
     331                 :             : 
     332                 :             :     /*
     333                 :             :      * This will be hit every time you answer yes to the dialog "The
     334                 :             :      * current transaction has changed. Would you like to record it.
     335                 :             :      */
     336                 :          37 :     PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
     337                 :             :            " old amount %s %s, new amount %s",
     338                 :             :            trans->description, split->memo,
     339                 :             :            gnc_num_dbg_to_string (xaccSplitGetAmount(split)),
     340                 :             :            gnc_commodity_get_mnemonic (currency),
     341                 :             :            gnc_num_dbg_to_string (xaccSplitGetValue(split)));
     342                 :             : 
     343                 :          37 :     xaccTransBeginEdit (trans);
     344                 :          37 :     xaccSplitSetAmount (split, value);
     345                 :          37 :     xaccTransCommitEdit (trans);
     346                 :          37 :     LEAVE ("(split=%p)", split);
     347                 :          37 :     return true;
     348                 :             : }
     349                 :             : 
     350                 :             : /* ================================================================ */
     351                 :             : 
     352                 :             : 
     353                 :             : static void
     354                 :           0 : AccountScrubImbalance (Account *acc, bool descendants,
     355                 :             :                        QofPercentageFunc percentagefunc)
     356                 :             : {
     357                 :           0 :     const char *message = _("Looking for imbalances in transaction date %s: %u of %zu");
     358                 :             : 
     359                 :           0 :     if (!acc) return;
     360                 :             : 
     361                 :           0 :     QofBook *book = qof_session_get_book (gnc_get_current_session ());
     362                 :           0 :     Account *root = gnc_book_get_root_account (book);
     363                 :           0 :     auto transactions = get_all_transactions (acc, descendants);
     364                 :           0 :     auto count = transactions.size();
     365                 :           0 :     auto curr_trans = 0;
     366                 :             : 
     367                 :           0 :     scrub_depth++;
     368                 :           0 :     for (auto trans : transactions)
     369                 :             :     {
     370                 :           0 :         if (abort_now) break;
     371                 :             : 
     372                 :           0 :         PINFO("Start processing transaction %d of %zu", curr_trans + 1, count);
     373                 :             : 
     374                 :           0 :         if (curr_trans % 10 == 0)
     375                 :             :         {
     376                 :           0 :             char *date = qof_print_date (xaccTransGetDate (trans));
     377                 :           0 :             char *progress_msg = g_strdup_printf (message, date, curr_trans, count);
     378                 :           0 :             (percentagefunc)(progress_msg, (100 * curr_trans) / count);
     379                 :           0 :             g_free (progress_msg);
     380                 :           0 :             g_free (date);
     381                 :             :         }
     382                 :             : 
     383                 :           0 :         TransScrubOrphansFast (trans, root);
     384                 :           0 :         xaccTransScrubCurrency(trans);
     385                 :           0 :         xaccTransScrubImbalance (trans, root, nullptr);
     386                 :             : 
     387                 :           0 :         PINFO("Finished processing transaction %d of %zu", curr_trans + 1, count);
     388                 :           0 :         curr_trans++;
     389                 :             :     }
     390                 :           0 :     (percentagefunc)(nullptr, -1.0);
     391                 :           0 :     scrub_depth--;
     392                 :           0 : }
     393                 :             : 
     394                 :             : void
     395                 :        2955 : xaccTransScrubSplits (Transaction *trans)
     396                 :             : {
     397                 :        2955 :     if (!trans) return;
     398                 :             : 
     399                 :        2955 :     gnc_commodity *currency = xaccTransGetCurrency (trans);
     400                 :        2955 :     if (!currency)
     401                 :         166 :         PERR ("Transaction doesn't have a currency!");
     402                 :             : 
     403                 :        2955 :     bool must_scrub = false;
     404                 :             : 
     405                 :        8465 :     for (GList *n = xaccTransGetSplitList (trans); !must_scrub && n; n = g_list_next (n))
     406                 :        5510 :         if (split_scrub_or_dry_run (GNC_SPLIT(n->data), true))
     407                 :         555 :             must_scrub = true;
     408                 :             : 
     409                 :        2955 :     if (!must_scrub)
     410                 :        2400 :         return;
     411                 :             : 
     412                 :         555 :     xaccTransBeginEdit(trans);
     413                 :             :     /* The split scrub expects the transaction to have a currency! */
     414                 :             : 
     415                 :        1641 :     for (GList *n = xaccTransGetSplitList (trans); n; n = g_list_next (n))
     416                 :        1086 :         xaccSplitScrub (GNC_SPLIT(n->data));
     417                 :             : 
     418                 :         555 :     xaccTransCommitEdit(trans);
     419                 :             : }
     420                 :             : 
     421                 :             : /* ================================================================ */
     422                 :             : 
     423                 :             : void
     424                 :        2730 : xaccSplitScrub (Split *split)
     425                 :             : {
     426                 :        2730 :     split_scrub_or_dry_run (split, false);
     427                 :        2730 : }
     428                 :             : 
     429                 :             : /* ================================================================ */
     430                 :             : 
     431                 :             : 
     432                 :             : void
     433                 :           0 : xaccAccountTreeScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
     434                 :             : {
     435                 :           0 :     AccountScrubImbalance (acc, true, percentagefunc);
     436                 :           0 : }
     437                 :             : 
     438                 :             : void
     439                 :           0 : xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
     440                 :             : {
     441                 :           0 :     AccountScrubImbalance (acc, false, percentagefunc);
     442                 :           0 : }
     443                 :             : 
     444                 :             : static Split *
     445                 :          38 : get_balance_split (Transaction *trans, Account *root, Account *account,
     446                 :             :                    gnc_commodity *commodity)
     447                 :             : {
     448                 :             :     Split *balance_split;
     449                 :             :     gchar *accname;
     450                 :             : 
     451                 :          38 :     if (!account ||
     452                 :           0 :         !gnc_commodity_equiv (commodity, xaccAccountGetCommodity(account)))
     453                 :             :     {
     454                 :          38 :         if (!root)
     455                 :             :         {
     456                 :          38 :             root = gnc_book_get_root_account (xaccTransGetBook (trans));
     457                 :          38 :             if (nullptr == root)
     458                 :             :             {
     459                 :             :                 /* This can't occur, things should be in books */
     460                 :           0 :                 PERR ("Bad data corruption, no root account in book");
     461                 :           0 :                 return nullptr;
     462                 :             :             }
     463                 :             :         }
     464                 :          38 :         accname = g_strconcat (_("Imbalance"), "-",
     465                 :             :                                gnc_commodity_get_mnemonic (commodity), nullptr);
     466                 :          38 :         account = xaccScrubUtilityGetOrMakeAccount (root, commodity,
     467                 :             :                                                     accname, ACCT_TYPE_BANK,
     468                 :             :                                                     FALSE, TRUE);
     469                 :          38 :         g_free (accname);
     470                 :          38 :         if (!account)
     471                 :             :         {
     472                 :           0 :             PERR ("Can't get balancing account");
     473                 :           0 :             return nullptr;
     474                 :             :         }
     475                 :             :     }
     476                 :             : 
     477                 :          38 :     balance_split = xaccTransFindSplitByAccount(trans, account);
     478                 :             : 
     479                 :             :     /* Put split into account before setting split value */
     480                 :          38 :     if (!balance_split)
     481                 :             :     {
     482                 :          27 :         balance_split = xaccMallocSplit (qof_instance_get_book(trans));
     483                 :             : 
     484                 :          27 :         xaccTransBeginEdit (trans);
     485                 :          27 :         xaccSplitSetParent(balance_split, trans);
     486                 :          27 :         xaccSplitSetAccount(balance_split, account);
     487                 :          27 :         xaccTransCommitEdit (trans);
     488                 :             :     }
     489                 :             : 
     490                 :          38 :     return balance_split;
     491                 :             : }
     492                 :             : 
     493                 :             : static gnc_commodity*
     494                 :          79 : find_root_currency(void)
     495                 :             : {
     496                 :          79 :     QofSession *sess = gnc_get_current_session ();
     497                 :          79 :     Account *root = gnc_book_get_root_account (qof_session_get_book (sess));
     498                 :          79 :     gnc_commodity *root_currency = xaccAccountGetCommodity (root);
     499                 :             : 
     500                 :             :     /* Some older books may not have a currency set on the root
     501                 :             :      * account. In that case find the first top-level INCOME account
     502                 :             :      * and use its currency. */
     503                 :          79 :     if (!root_currency)
     504                 :             :     {
     505                 :          79 :          GList *children = gnc_account_get_children (root);
     506                 :          79 :          for (GList *node = children; node && !root_currency;
     507                 :           0 :               node = g_list_next (node))
     508                 :             :          {
     509                 :           0 :               Account *child = GNC_ACCOUNT (node->data);
     510                 :           0 :               if (xaccAccountGetType (child) == ACCT_TYPE_INCOME)
     511                 :           0 :                    root_currency = xaccAccountGetCommodity (child);
     512                 :             :          }
     513                 :          79 :          g_list_free (children);
     514                 :             :     }
     515                 :          79 :     return root_currency;
     516                 :             : }
     517                 :             : 
     518                 :             : /* Get the trading split for a given commodity, creating it (and the
     519                 :             :    necessary parent accounts) if it doesn't exist. */
     520                 :             : static Split *
     521                 :           0 : get_trading_split (Transaction *trans, Account *base,
     522                 :             :                    gnc_commodity *commodity)
     523                 :             : {
     524                 :             :     Split *balance_split;
     525                 :             :     Account *trading_account;
     526                 :             :     Account *ns_account;
     527                 :             :     Account *account;
     528                 :           0 :     Account* root = gnc_book_get_root_account (xaccTransGetBook (trans));
     529                 :             : 
     530                 :           0 :     trading_account = xaccScrubUtilityGetOrMakeAccount (root,
     531                 :             :                                                         nullptr,
     532                 :           0 :                                                         _("Trading"),
     533                 :             :                                                         ACCT_TYPE_TRADING,
     534                 :             :                                                         TRUE, FALSE);
     535                 :           0 :     if (!trading_account)
     536                 :             :     {
     537                 :           0 :         PERR ("Can't get trading account");
     538                 :           0 :         return nullptr;
     539                 :             :     }
     540                 :             : 
     541                 :           0 :     ns_account = xaccScrubUtilityGetOrMakeAccount (trading_account,
     542                 :             :                                                    nullptr,
     543                 :             :                                                    gnc_commodity_get_namespace(commodity),
     544                 :             :                                                    ACCT_TYPE_TRADING,
     545                 :             :                                                    TRUE, TRUE);
     546                 :           0 :     if (!ns_account)
     547                 :             :     {
     548                 :           0 :         PERR ("Can't get namespace account");
     549                 :           0 :         return nullptr;
     550                 :             :     }
     551                 :             : 
     552                 :           0 :     account = xaccScrubUtilityGetOrMakeAccount (ns_account, commodity,
     553                 :             :                                                 gnc_commodity_get_mnemonic(commodity),
     554                 :             :                                                 ACCT_TYPE_TRADING,
     555                 :             :                                                 FALSE, FALSE);
     556                 :           0 :     if (!account)
     557                 :             :     {
     558                 :           0 :         PERR ("Can't get commodity account");
     559                 :           0 :         return nullptr;
     560                 :             :     }
     561                 :             : 
     562                 :             : 
     563                 :           0 :     balance_split = xaccTransFindSplitByAccount(trans, account);
     564                 :             : 
     565                 :             :     /* Put split into account before setting split value */
     566                 :           0 :     if (!balance_split)
     567                 :             :     {
     568                 :           0 :         balance_split = xaccMallocSplit (qof_instance_get_book(trans));
     569                 :             : 
     570                 :           0 :         xaccTransBeginEdit (trans);
     571                 :           0 :         xaccSplitSetParent(balance_split, trans);
     572                 :           0 :         xaccSplitSetAccount(balance_split, account);
     573                 :           0 :         xaccTransCommitEdit (trans);
     574                 :             :     }
     575                 :             : 
     576                 :           0 :     return balance_split;
     577                 :             : }
     578                 :             : 
     579                 :             : static void
     580                 :          38 : add_balance_split (Transaction *trans, gnc_numeric imbalance,
     581                 :             :                    Account *root, Account *account)
     582                 :             : {
     583                 :             :     const gnc_commodity *commodity;
     584                 :             :     gnc_numeric old_value, new_value;
     585                 :             :     Split *balance_split;
     586                 :          38 :     gnc_commodity *currency = xaccTransGetCurrency (trans);
     587                 :             : 
     588                 :          38 :     balance_split = get_balance_split(trans, root, account, currency);
     589                 :          38 :     if (!balance_split)
     590                 :             :     {
     591                 :             :         /* Error already logged */
     592                 :           0 :         LEAVE("");
     593                 :           0 :         return;
     594                 :             :     }
     595                 :          38 :     account = xaccSplitGetAccount(balance_split);
     596                 :             : 
     597                 :          38 :     xaccTransBeginEdit (trans);
     598                 :             : 
     599                 :          38 :     old_value = xaccSplitGetValue (balance_split);
     600                 :             : 
     601                 :             :     /* Note: We have to round for the commodity's fraction, NOT any
     602                 :             :      * already existing denominator (bug #104343), because either one
     603                 :             :      * of the denominators might already be reduced.  */
     604                 :          38 :     new_value = gnc_numeric_sub (old_value, imbalance,
     605                 :          38 :                                  gnc_commodity_get_fraction(currency),
     606                 :             :                                  GNC_HOW_RND_ROUND_HALF_UP);
     607                 :             : 
     608                 :          38 :     xaccSplitSetValue (balance_split, new_value);
     609                 :             : 
     610                 :          38 :     commodity = xaccAccountGetCommodity (account);
     611                 :          38 :     if (gnc_commodity_equiv (currency, commodity))
     612                 :             :     {
     613                 :          38 :         xaccSplitSetAmount (balance_split, new_value);
     614                 :             :     }
     615                 :             : 
     616                 :          38 :     xaccSplitScrub (balance_split);
     617                 :          38 :     xaccTransCommitEdit (trans);
     618                 :             : }
     619                 :             : 
     620                 :             : /* Balance a transaction without trading accounts. */
     621                 :             : static void
     622                 :          38 : gnc_transaction_balance_no_trading (Transaction *trans, Account *root,
     623                 :             :                                     Account *account)
     624                 :             : {
     625                 :          38 :     gnc_numeric imbalance  = xaccTransGetImbalanceValue (trans);
     626                 :             : 
     627                 :             :     /* Make the value sum to zero */
     628                 :          38 :     if (! gnc_numeric_zero_p (imbalance))
     629                 :             :     {
     630                 :          38 :         PINFO ("Value unbalanced transaction");
     631                 :             : 
     632                 :          38 :         add_balance_split (trans, imbalance, root, account);
     633                 :             :     }
     634                 :             : 
     635                 :          38 : }
     636                 :             : 
     637                 :             : static gnc_numeric
     638                 :           0 : gnc_transaction_get_commodity_imbalance (Transaction *trans,
     639                 :             :                                          gnc_commodity *commodity)
     640                 :             : {
     641                 :             :     /* Find the value imbalance in this commodity */
     642                 :           0 :     gnc_numeric val_imbalance = gnc_numeric_zero();
     643                 :           0 :     GList *splits = nullptr;
     644                 :           0 :     for (splits = trans->splits; splits; splits = splits->next)
     645                 :             :     {
     646                 :           0 :         Split *split = GNC_SPLIT(splits->data);
     647                 :             :         gnc_commodity *split_commodity =
     648                 :           0 :             xaccAccountGetCommodity(xaccSplitGetAccount(split));
     649                 :           0 :         if (xaccTransStillHasSplit (trans, split) &&
     650                 :           0 :             gnc_commodity_equal (commodity, split_commodity))
     651                 :           0 :             val_imbalance = gnc_numeric_add (val_imbalance,
     652                 :             :                                              xaccSplitGetValue (split),
     653                 :             :                                              GNC_DENOM_AUTO,
     654                 :             :                                              GNC_HOW_DENOM_EXACT);
     655                 :             :     }
     656                 :           0 :     return val_imbalance;
     657                 :             : }
     658                 :             : 
     659                 :             : /* GFunc wrapper for xaccSplitDestroy */
     660                 :             : static void
     661                 :           0 : destroy_split (void* ptr)
     662                 :             : {
     663                 :           0 :     Split *split = GNC_SPLIT (ptr);
     664                 :           0 :     if (split)
     665                 :           0 :         xaccSplitDestroy (split);
     666                 :           0 : }
     667                 :             : 
     668                 :             : /* Balancing transactions with trading accounts works best when
     669                 :             :  * starting with no trading splits.
     670                 :             :  */
     671                 :             : static void
     672                 :           0 : xaccTransClearTradingSplits (Transaction *trans)
     673                 :             : {
     674                 :           0 :     GList *trading_splits = nullptr;
     675                 :             : 
     676                 :           0 :     for (GList* node = trans->splits; node; node = node->next)
     677                 :             :     {
     678                 :           0 :          Split* split = GNC_SPLIT(node->data);
     679                 :           0 :          Account* acc = nullptr;
     680                 :           0 :          if (!split)
     681                 :           0 :               continue;
     682                 :           0 :          acc = xaccSplitGetAccount(split);
     683                 :           0 :          if (acc && xaccAccountGetType(acc) == ACCT_TYPE_TRADING)
     684                 :           0 :             trading_splits = g_list_prepend (trading_splits, node->data);
     685                 :             :     }
     686                 :             : 
     687                 :           0 :     if (!trading_splits)
     688                 :           0 :         return;
     689                 :             : 
     690                 :           0 :     xaccTransBeginEdit (trans);
     691                 :             :     /* destroy_splits doesn't actually free the splits but this gets
     692                 :             :      * the list itself freed.
     693                 :             :      */
     694                 :           0 :     g_list_free_full (trading_splits, destroy_split);
     695                 :           0 :     xaccTransCommitEdit (trans);
     696                 :             : }
     697                 :             : 
     698                 :             : static void
     699                 :           0 : gnc_transaction_balance_trading (Transaction *trans, Account *root)
     700                 :             : {
     701                 :             :     MonetaryList *imbal_list;
     702                 :             :     MonetaryList *imbalance_commod;
     703                 :           0 :     Split *balance_split = nullptr;
     704                 :             : 
     705                 :             :     /* If the transaction is balanced, nothing more to do */
     706                 :           0 :     imbal_list = xaccTransGetImbalance (trans);
     707                 :           0 :     if (!imbal_list)
     708                 :             :     {
     709                 :           0 :         LEAVE("transaction is balanced");
     710                 :           0 :         return;
     711                 :             :     }
     712                 :             : 
     713                 :           0 :     PINFO ("Currency unbalanced transaction");
     714                 :             : 
     715                 :           0 :     for (imbalance_commod = imbal_list; imbalance_commod;
     716                 :           0 :          imbalance_commod = imbalance_commod->next)
     717                 :             :     {
     718                 :           0 :         auto imbal_mon = static_cast<gnc_monetary*>(imbalance_commod->data);
     719                 :             :         gnc_commodity *commodity;
     720                 :             :         gnc_numeric old_amount, new_amount;
     721                 :           0 :         const gnc_commodity *txn_curr = xaccTransGetCurrency (trans);
     722                 :             : 
     723                 :           0 :         commodity = gnc_monetary_commodity (*imbal_mon);
     724                 :             : 
     725                 :           0 :         balance_split = get_trading_split(trans, root, commodity);
     726                 :           0 :         if (!balance_split)
     727                 :             :         {
     728                 :             :             /* Error already logged */
     729                 :           0 :             gnc_monetary_list_free(imbal_list);
     730                 :           0 :             LEAVE("");
     731                 :           0 :             return;
     732                 :             :         }
     733                 :             : 
     734                 :           0 :         xaccTransBeginEdit (trans);
     735                 :             : 
     736                 :           0 :         old_amount = xaccSplitGetAmount (balance_split);
     737                 :           0 :         new_amount = gnc_numeric_sub (old_amount, gnc_monetary_value(*imbal_mon),
     738                 :           0 :                                       gnc_commodity_get_fraction(commodity),
     739                 :             :                                       GNC_HOW_RND_ROUND_HALF_UP);
     740                 :             : 
     741                 :           0 :         xaccSplitSetAmount (balance_split, new_amount);
     742                 :             : 
     743                 :           0 :         if (gnc_commodity_equal (txn_curr, commodity))
     744                 :             :         {
     745                 :             :             /* Imbalance commodity is the transaction currency, value in the
     746                 :             :                split must be the same as the amount */
     747                 :           0 :             xaccSplitSetValue (balance_split, new_amount);
     748                 :             :         }
     749                 :             :         else
     750                 :             :         {
     751                 :           0 :             gnc_numeric val_imbalance = gnc_transaction_get_commodity_imbalance (trans,            commodity);
     752                 :             : 
     753                 :           0 :             gnc_numeric old_value = xaccSplitGetValue (balance_split);
     754                 :           0 :             gnc_numeric new_value = gnc_numeric_sub (old_value, val_imbalance,
     755                 :           0 :                                          gnc_commodity_get_fraction(txn_curr),
     756                 :             :                                          GNC_HOW_RND_ROUND_HALF_UP);
     757                 :             : 
     758                 :           0 :             xaccSplitSetValue (balance_split, new_value);
     759                 :             :         }
     760                 :             : 
     761                 :           0 :         xaccSplitScrub (balance_split);
     762                 :           0 :         xaccTransCommitEdit (trans);
     763                 :             :     }
     764                 :             : 
     765                 :           0 :     gnc_monetary_list_free(imbal_list);
     766                 :             : }
     767                 :             : 
     768                 :             : /** Balance the transaction by adding more trading splits. This shouldn't
     769                 :             :  * ordinarily be necessary.
     770                 :             :  * @param trans the transaction to balance
     771                 :             :  * @param root the root account
     772                 :             :  */
     773                 :             : static void
     774                 :           0 : gnc_transaction_balance_trading_more_splits (Transaction *trans, Account *root)
     775                 :             : {
     776                 :             :     /* Copy the split list so we don't see the splits we're adding */
     777                 :           0 :     GList *splits_dup = g_list_copy(trans->splits), *splits = nullptr;
     778                 :           0 :     const gnc_commodity  *txn_curr = xaccTransGetCurrency (trans);
     779                 :           0 :     for (splits = splits_dup; splits; splits = splits->next)
     780                 :             :     {
     781                 :           0 :         Split *split = GNC_SPLIT(splits->data);
     782                 :           0 :         if (! xaccTransStillHasSplit(trans, split)) continue;
     783                 :           0 :         if (!gnc_numeric_zero_p(xaccSplitGetValue(split)) &&
     784                 :           0 :             gnc_numeric_zero_p(xaccSplitGetAmount(split)))
     785                 :             :         {
     786                 :             :             gnc_commodity *commodity;
     787                 :             :             gnc_numeric old_value, new_value;
     788                 :             :             Split *balance_split;
     789                 :             : 
     790                 :           0 :             commodity = xaccAccountGetCommodity(xaccSplitGetAccount(split));
     791                 :           0 :             if (!commodity)
     792                 :             :             {
     793                 :           0 :                 PERR("Split has no commodity");
     794                 :           0 :                 continue;
     795                 :             :             }
     796                 :           0 :             balance_split = get_trading_split(trans, root, commodity);
     797                 :           0 :             if (!balance_split)
     798                 :             :             {
     799                 :             :                 /* Error already logged */
     800                 :           0 :                 LEAVE("");
     801                 :           0 :                 return;
     802                 :             :             }
     803                 :           0 :             xaccTransBeginEdit (trans);
     804                 :             : 
     805                 :           0 :             old_value = xaccSplitGetValue (balance_split);
     806                 :           0 :             new_value = gnc_numeric_sub (old_value, xaccSplitGetValue(split),
     807                 :           0 :                                          gnc_commodity_get_fraction(txn_curr),
     808                 :             :                                          GNC_HOW_RND_ROUND_HALF_UP);
     809                 :           0 :             xaccSplitSetValue (balance_split, new_value);
     810                 :             : 
     811                 :             :             /* Don't change the balance split's amount since the amount
     812                 :             :                is zero in the split we're working on */
     813                 :             : 
     814                 :           0 :             xaccSplitScrub (balance_split);
     815                 :           0 :             xaccTransCommitEdit (trans);
     816                 :             :         }
     817                 :             :     }
     818                 :             : 
     819                 :           0 :     g_list_free(splits_dup);
     820                 :             : }
     821                 :             : 
     822                 :             : /** Correct transaction imbalances.
     823                 :             :  * @param trans The Transaction
     824                 :             :  * @param root The (hidden) root account, for the book default currency.
     825                 :             :  * @param account The account whose currency in which to balance.
     826                 :             :  */
     827                 :             : 
     828                 :             : void
     829                 :        2955 : xaccTransScrubImbalance (Transaction *trans, Account *root,
     830                 :             :                          Account *account)
     831                 :             : {
     832                 :             :     gnc_numeric imbalance;
     833                 :             : 
     834                 :        5910 :     if (!trans) return;
     835                 :             : 
     836                 :        2955 :     ENTER ("()");
     837                 :             : 
     838                 :             :     /* Must look for orphan splits even if there is no imbalance. */
     839                 :        2955 :     xaccTransScrubSplits (trans);
     840                 :             : 
     841                 :             :     /* Return immediately if things are balanced. */
     842                 :        2955 :     if (xaccTransIsBalanced (trans))
     843                 :             :     {
     844                 :        2917 :         LEAVE ("transaction is balanced");
     845                 :        2917 :         return;
     846                 :             :     }
     847                 :             : 
     848                 :          38 :     if (! xaccTransUseTradingAccounts (trans))
     849                 :             :     {
     850                 :          38 :         gnc_transaction_balance_no_trading (trans, root, account);
     851                 :          38 :         LEAVE ("transaction balanced, no managed trading accounts");
     852                 :          38 :         return;
     853                 :             :     }
     854                 :             : 
     855                 :           0 :     xaccTransClearTradingSplits (trans);
     856                 :           0 :     imbalance = xaccTransGetImbalanceValue (trans);
     857                 :           0 :     if (! gnc_numeric_zero_p (imbalance))
     858                 :             :     {
     859                 :           0 :         PINFO ("Value unbalanced transaction");
     860                 :             : 
     861                 :           0 :         add_balance_split (trans, imbalance, root, account);
     862                 :             :     }
     863                 :             : 
     864                 :           0 :     gnc_transaction_balance_trading (trans, root);
     865                 :           0 :     if (gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans)))
     866                 :             :     {
     867                 :           0 :         LEAVE ("()");
     868                 :           0 :         return;
     869                 :             :     }
     870                 :             :     /* If the transaction is still not balanced, it's probably because there
     871                 :             :        are splits with zero amount and non-zero value.  These are usually
     872                 :             :        realized gain/loss splits.  Add a reversing split for each of them to
     873                 :             :        balance the value. */
     874                 :             : 
     875                 :           0 :     gnc_transaction_balance_trading_more_splits (trans, root);
     876                 :           0 :     if (!gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans)))
     877                 :           0 :         PERR("Balancing currencies unbalanced value");
     878                 :             : 
     879                 :             : }
     880                 :             : 
     881                 :             : /* ================================================================ */
     882                 :             : /* The xaccTransFindCommonCurrency () method returns
     883                 :             :  *    a gnc_commodity indicating a currency denomination that all
     884                 :             :  *    of the splits in this transaction have in common, using the
     885                 :             :  *    old/obsolete currency/security fields of the split accounts.
     886                 :             :  */
     887                 :             : 
     888                 :             : static gnc_commodity *
     889                 :           0 : FindCommonExclSCurrency (SplitList *splits,
     890                 :             :                          gnc_commodity * ra, gnc_commodity * rb,
     891                 :             :                          Split *excl_split)
     892                 :             : {
     893                 :             :     GList *node;
     894                 :             : 
     895                 :           0 :     if (!splits) return nullptr;
     896                 :             : 
     897                 :           0 :     for (node = splits; node; node = node->next)
     898                 :             :     {
     899                 :           0 :         Split *s = GNC_SPLIT(node->data);
     900                 :             :         gnc_commodity * sa, * sb;
     901                 :             : 
     902                 :           0 :         if (s == excl_split) continue;
     903                 :             : 
     904                 :           0 :         g_return_val_if_fail (s->acc, nullptr);
     905                 :             : 
     906                 :           0 :         sa = DxaccAccountGetCurrency (s->acc);
     907                 :           0 :         sb = xaccAccountGetCommodity (s->acc);
     908                 :             : 
     909                 :           0 :         if (ra && rb)
     910                 :             :         {
     911                 :           0 :             int aa = !gnc_commodity_equiv(ra, sa);
     912                 :           0 :             int ab = !gnc_commodity_equiv(ra, sb);
     913                 :           0 :             int ba = !gnc_commodity_equiv(rb, sa);
     914                 :           0 :             int bb = !gnc_commodity_equiv(rb, sb);
     915                 :             : 
     916                 :           0 :             if ( (!aa) && bb) rb = nullptr;
     917                 :           0 :             else if ( (!ab) && ba) rb = nullptr;
     918                 :           0 :             else if ( (!ba) && ab) ra = nullptr;
     919                 :           0 :             else if ( (!bb) && aa) ra = nullptr;
     920                 :           0 :             else if ( aa && bb && ab && ba )
     921                 :             :             {
     922                 :           0 :                 ra = nullptr;
     923                 :           0 :                 rb = nullptr;
     924                 :             :             }
     925                 :             : 
     926                 :           0 :             if (!ra)
     927                 :             :             {
     928                 :           0 :                 ra = rb;
     929                 :           0 :                 rb = nullptr;
     930                 :             :             }
     931                 :           0 :         }
     932                 :           0 :         else if (ra && !rb)
     933                 :             :         {
     934                 :           0 :             int aa = !gnc_commodity_equiv(ra, sa);
     935                 :           0 :             int ab = !gnc_commodity_equiv(ra, sb);
     936                 :           0 :             if ( aa && ab ) ra = nullptr;
     937                 :           0 :         }
     938                 :           0 :         else if (!ra && rb)
     939                 :             :         {
     940                 :           0 :             int aa = !gnc_commodity_equiv(rb, sa);
     941                 :           0 :             int ab = !gnc_commodity_equiv(rb, sb);
     942                 :           0 :             ra = ( aa && ab ) ? nullptr : rb;
     943                 :             :         }
     944                 :             : 
     945                 :           0 :         if ((!ra) && (!rb)) return nullptr;
     946                 :             :     }
     947                 :             : 
     948                 :           0 :     return (ra);
     949                 :             : }
     950                 :             : 
     951                 :             : /* This is the wrapper for those calls (i.e. the older ones) which
     952                 :             :  * don't exclude one split from the splitlist when looking for a
     953                 :             :  * common currency.
     954                 :             :  */
     955                 :             : static gnc_commodity *
     956                 :           0 : FindCommonCurrency (GList *splits, gnc_commodity * ra, gnc_commodity * rb)
     957                 :             : {
     958                 :           0 :     return FindCommonExclSCurrency(splits, ra, rb, nullptr);
     959                 :             : }
     960                 :             : 
     961                 :             : static gnc_commodity *
     962                 :           0 : xaccTransFindOldCommonCurrency (Transaction *trans, QofBook *book)
     963                 :             : {
     964                 :             :     gnc_commodity *ra, *rb, *retval;
     965                 :             :     Split *split;
     966                 :             : 
     967                 :           0 :     if (!trans) return nullptr;
     968                 :             : 
     969                 :           0 :     if (trans->splits == nullptr) return nullptr;
     970                 :             : 
     971                 :           0 :     g_return_val_if_fail (book, nullptr);
     972                 :             : 
     973                 :           0 :     split = GNC_SPLIT(trans->splits->data);
     974                 :             : 
     975                 :           0 :     if (!split || nullptr == split->acc) return nullptr;
     976                 :             : 
     977                 :           0 :     ra = DxaccAccountGetCurrency (split->acc);
     978                 :           0 :     rb = xaccAccountGetCommodity (split->acc);
     979                 :             : 
     980                 :           0 :     retval = FindCommonCurrency (trans->splits, ra, rb);
     981                 :             : 
     982                 :           0 :     if (retval && !gnc_commodity_is_currency(retval))
     983                 :           0 :         retval = nullptr;
     984                 :             : 
     985                 :           0 :     return retval;
     986                 :             : }
     987                 :             : 
     988                 :             : /* Test the currency of the splits and find the most common and return
     989                 :             :  * it, or nullptr if there is no currency more common than the
     990                 :             :  * others -- or none at all.
     991                 :             :  */
     992                 :             : typedef struct
     993                 :             : {
     994                 :             :     gnc_commodity *commodity;
     995                 :             :     unsigned int count;
     996                 :             : } CommodityCount;
     997                 :             : 
     998                 :             : static gint
     999                 :         202 : commodity_equal (gconstpointer a, gconstpointer b)
    1000                 :             : {
    1001                 :         202 :     CommodityCount *cc = (CommodityCount*)a;
    1002                 :         202 :     gnc_commodity *com = (gnc_commodity*)b;
    1003                 :         404 :     if ( cc == nullptr || cc->commodity == nullptr ||
    1004                 :         202 :          !GNC_IS_COMMODITY( cc->commodity ) ) return -1;
    1005                 :         202 :     if ( com == nullptr || !GNC_IS_COMMODITY( com ) ) return 1;
    1006                 :         202 :     if ( gnc_commodity_equal(cc->commodity, com) )
    1007                 :         202 :         return 0;
    1008                 :           0 :     return 1;
    1009                 :             : }
    1010                 :             : 
    1011                 :             : static gint
    1012                 :           0 : commodity_compare( gconstpointer a, gconstpointer b)
    1013                 :             : {
    1014                 :           0 :     CommodityCount *ca = (CommodityCount*)a, *cb = (CommodityCount*)b;
    1015                 :           0 :     if (ca == nullptr || ca->commodity == nullptr ||
    1016                 :           0 :         !GNC_IS_COMMODITY( ca->commodity ) )
    1017                 :             :     {
    1018                 :           0 :         if (cb == nullptr || cb->commodity == nullptr ||
    1019                 :           0 :             !GNC_IS_COMMODITY( cb->commodity ) )
    1020                 :           0 :             return 0;
    1021                 :           0 :         return -1;
    1022                 :             :     }
    1023                 :           0 :     if (cb == nullptr || cb->commodity == nullptr ||
    1024                 :           0 :         !GNC_IS_COMMODITY( cb->commodity ) )
    1025                 :           0 :         return 1;
    1026                 :           0 :     if (ca->count == cb->count)
    1027                 :           0 :         return 0;
    1028                 :           0 :     return ca->count > cb->count ? 1 : -1;
    1029                 :             : }
    1030                 :             : 
    1031                 :             : /* Find the commodities in the account of each of the splits of a
    1032                 :             :  * transaction, and rank them by how many splits in which they
    1033                 :             :  * occur. Commodities which are currencies count more than those which
    1034                 :             :  * aren't, because for simple buy and sell transactions it makes
    1035                 :             :  * slightly more sense for the transaction commodity to be the
    1036                 :             :  * currency -- to the extent that it makes sense for a transaction to
    1037                 :             :  * have a currency at all. jralls, 2010-11-02 */
    1038                 :             : 
    1039                 :             : static gnc_commodity *
    1040                 :         198 : xaccTransFindCommonCurrency (Transaction *trans, QofBook *book)
    1041                 :             : {
    1042                 :             :     gnc_commodity *com_scratch;
    1043                 :         198 :     GList *node = nullptr;
    1044                 :         198 :     GSList *comlist = nullptr, *found = nullptr;
    1045                 :             : 
    1046                 :         198 :     if (!trans) return nullptr;
    1047                 :             : 
    1048                 :         198 :     if (trans->splits == nullptr) return nullptr;
    1049                 :             : 
    1050                 :         198 :     g_return_val_if_fail (book, nullptr);
    1051                 :             : 
    1052                 :             :     /* Find the most commonly used currency among the splits.  If a given split
    1053                 :             :        is in a non-currency commodity, then look for an ancestor account in a
    1054                 :             :        currency, but prefer currencies used directly in splits.  Ignore trading
    1055                 :             :        account splits in this whole process, they don't add any value to this algorithm. */
    1056                 :         601 :     for (node = trans->splits; node; node = node->next)
    1057                 :             :     {
    1058                 :         403 :         Split *s = GNC_SPLIT(node->data);
    1059                 :             :         unsigned int curr_weight;
    1060                 :             : 
    1061                 :         403 :         if (s == nullptr || s->acc == nullptr) continue;
    1062                 :         403 :         if (xaccAccountGetType(s->acc) == ACCT_TYPE_TRADING) continue;
    1063                 :         403 :         com_scratch = xaccAccountGetCommodity(s->acc);
    1064                 :         403 :         if (com_scratch && gnc_commodity_is_currency(com_scratch))
    1065                 :             :         {
    1066                 :          71 :             curr_weight = 3;
    1067                 :             :         }
    1068                 :             :         else
    1069                 :             :         {
    1070                 :         332 :             com_scratch = gnc_account_get_currency_or_parent(s->acc);
    1071                 :         332 :             if (com_scratch == nullptr) continue;
    1072                 :         329 :             curr_weight = 1;
    1073                 :             :         }
    1074                 :         400 :         if ( comlist )
    1075                 :             :         {
    1076                 :         202 :             found = g_slist_find_custom(comlist, com_scratch, commodity_equal);
    1077                 :             :         }
    1078                 :         400 :         if (comlist == nullptr || found == nullptr)
    1079                 :             :         {
    1080                 :         198 :             CommodityCount *count = g_slice_new0(CommodityCount);
    1081                 :         198 :             count->commodity = com_scratch;
    1082                 :         198 :             count->count = curr_weight;
    1083                 :         198 :             comlist = g_slist_append(comlist, count);
    1084                 :         198 :         }
    1085                 :             :         else
    1086                 :             :         {
    1087                 :         202 :             CommodityCount *count = (CommodityCount*)(found->data);
    1088                 :         202 :             count->count += curr_weight;
    1089                 :             :         }
    1090                 :             :     }
    1091                 :         198 :     found = g_slist_sort( comlist, commodity_compare);
    1092                 :             : 
    1093                 :         198 :     if ( found && found->data && (((CommodityCount*)(found->data))->commodity != nullptr))
    1094                 :             :     {
    1095                 :         198 :         return ((CommodityCount*)(found->data))->commodity;
    1096                 :             :     }
    1097                 :             :     /* We didn't find a currency in the current account structure, so try
    1098                 :             :      * an old one. */
    1099                 :           0 :     return xaccTransFindOldCommonCurrency( trans, book );
    1100                 :             : }
    1101                 :             : 
    1102                 :             : /* ================================================================ */
    1103                 :             : 
    1104                 :             : void
    1105                 :        1541 : xaccTransScrubCurrency (Transaction *trans)
    1106                 :             : {
    1107                 :             :     SplitList *node;
    1108                 :             :     gnc_commodity *currency;
    1109                 :             : 
    1110                 :        1541 :     if (!trans) return;
    1111                 :             : 
    1112                 :             :     /* If there are any orphaned splits in a transaction, then the
    1113                 :             :      * this routine will fail.  Therefore, we want to make sure that
    1114                 :             :      * there are no orphans (splits without parent account).
    1115                 :             :      */
    1116                 :        1541 :     xaccTransScrubOrphans (trans);
    1117                 :             : 
    1118                 :        1541 :     currency = xaccTransGetCurrency (trans);
    1119                 :        1541 :     if (currency && gnc_commodity_is_currency(currency)) return;
    1120                 :             : 
    1121                 :         198 :     currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans));
    1122                 :         198 :     if (currency)
    1123                 :             :     {
    1124                 :         198 :         xaccTransBeginEdit (trans);
    1125                 :         198 :         xaccTransSetCurrency (trans, currency);
    1126                 :         198 :         xaccTransCommitEdit (trans);
    1127                 :             :     }
    1128                 :             :     else
    1129                 :             :     {
    1130                 :           0 :         if (nullptr == trans->splits)
    1131                 :             :         {
    1132                 :           0 :             PWARN ("Transaction \"%s\" has no splits in it!", trans->description);
    1133                 :             :         }
    1134                 :             :         else
    1135                 :             :         {
    1136                 :             :             SplitList *node;
    1137                 :             :             char guid_str[GUID_ENCODING_LENGTH + 1];
    1138                 :           0 :             guid_to_string_buff(xaccTransGetGUID(trans), guid_str);
    1139                 :           0 :             PWARN ("no common transaction currency found for trans=\"%s\" (%s);",
    1140                 :             :                    trans->description, guid_str);
    1141                 :             : 
    1142                 :           0 :             for (node = trans->splits; node; node = node->next)
    1143                 :             :             {
    1144                 :           0 :                 Split *split = GNC_SPLIT(node->data);
    1145                 :           0 :                 if (nullptr == split->acc)
    1146                 :             :                 {
    1147                 :           0 :                     PWARN (" split=\"%s\" is not in any account!", split->memo);
    1148                 :             :                 }
    1149                 :             :                 else
    1150                 :             :                 {
    1151                 :           0 :                     gnc_commodity *currency = xaccAccountGetCommodity(split->acc);
    1152                 :           0 :                     PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"",
    1153                 :             :                            split->memo, xaccAccountGetName(split->acc),
    1154                 :             :                            gnc_commodity_get_mnemonic(currency));
    1155                 :             : 
    1156                 :           0 :                     xaccTransBeginEdit (trans);
    1157                 :           0 :                     xaccTransSetCurrency (trans, currency);
    1158                 :           0 :                     xaccTransCommitEdit (trans);
    1159                 :           0 :                     return;
    1160                 :             :                 }
    1161                 :             :             }
    1162                 :             :         }
    1163                 :           0 :         return;
    1164                 :             :     }
    1165                 :             : 
    1166                 :         601 :     for (node = trans->splits; node; node = node->next)
    1167                 :             :     {
    1168                 :         403 :         Split *sp = GNC_SPLIT(node->data);
    1169                 :             : 
    1170                 :         403 :         if (!gnc_numeric_equal(xaccSplitGetAmount (sp),
    1171                 :             :                                xaccSplitGetValue (sp)))
    1172                 :             :         {
    1173                 :             :             gnc_commodity *acc_currency;
    1174                 :             : 
    1175                 :         299 :             acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : nullptr;
    1176                 :         299 :             if (acc_currency == currency)
    1177                 :             :             {
    1178                 :             :                 /* This Split needs fixing: The transaction-currency equals
    1179                 :             :                  * the account-currency/commodity, but the amount/values are
    1180                 :             :                  * inequal i.e. they still correspond to the security
    1181                 :             :                  * (amount) and the currency (value). In the new model, the
    1182                 :             :                  * value is the amount in the account-commodity -- so it
    1183                 :             :                  * needs to be set to equal the amount (since the
    1184                 :             :                  * account-currency doesn't exist anymore).
    1185                 :             :                  *
    1186                 :             :                  * Note: Nevertheless we lose some information here. Namely,
    1187                 :             :                  * the information that the 'amount' in 'account-old-security'
    1188                 :             :                  * was worth 'value' in 'account-old-currency'. Maybe it would
    1189                 :             :                  * be better to store that information in the price database?
    1190                 :             :                  * But then, for old currency transactions there is still the
    1191                 :             :                  * 'other' transaction, which is going to keep that
    1192                 :             :                  * information. So I don't bother with that here. -- cstim,
    1193                 :             :                  * 2002/11/20. */
    1194                 :             : 
    1195                 :           0 :                 PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
    1196                 :             :                        " old amount %s %s, new amount %s",
    1197                 :             :                        trans->description, sp->memo,
    1198                 :             :                        gnc_num_dbg_to_string (xaccSplitGetAmount(sp)),
    1199                 :             :                        gnc_commodity_get_mnemonic (currency),
    1200                 :             :                        gnc_num_dbg_to_string (xaccSplitGetValue(sp)));
    1201                 :           0 :                 xaccTransBeginEdit (trans);
    1202                 :           0 :                 xaccSplitSetAmount (sp, xaccSplitGetValue(sp));
    1203                 :           0 :                 xaccTransCommitEdit (trans);
    1204                 :             :             }
    1205                 :             :             /*else
    1206                 :             :               {
    1207                 :             :               PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
    1208                 :             :               xaccSplitGetMemo (sp),
    1209                 :             :               gnc_num_dbg_to_string (amount),
    1210                 :             :               gnc_commodity_get_mnemonic (currency),
    1211                 :             :               gnc_num_dbg_to_string (value),
    1212                 :             :               gnc_commodity_get_mnemonic (acc_currency));
    1213                 :             :               }*/
    1214                 :             :         }
    1215                 :             :     }
    1216                 :             : 
    1217                 :             : }
    1218                 :             : 
    1219                 :             : /* ================================================================ */
    1220                 :             : 
    1221                 :             : void
    1222                 :        2533 : xaccAccountScrubCommodity (Account *account)
    1223                 :             : {
    1224                 :             :     gnc_commodity *commodity;
    1225                 :             : 
    1226                 :        2533 :     if (!account) return;
    1227                 :        2533 :     if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return;
    1228                 :             : 
    1229                 :        2458 :     commodity = xaccAccountGetCommodity (account);
    1230                 :        2458 :     if (commodity) return;
    1231                 :             : 
    1232                 :             :     /* Use the 'obsolete' routines to try to figure out what the
    1233                 :             :      * account commodity should have been. */
    1234                 :         908 :     commodity = xaccAccountGetCommodity (account);
    1235                 :         908 :     if (commodity)
    1236                 :             :     {
    1237                 :           0 :         xaccAccountSetCommodity (account, commodity);
    1238                 :           0 :         return;
    1239                 :             :     }
    1240                 :             : 
    1241                 :         908 :     commodity = DxaccAccountGetCurrency (account);
    1242                 :         908 :     if (commodity)
    1243                 :             :     {
    1244                 :           0 :         xaccAccountSetCommodity (account, commodity);
    1245                 :           0 :         return;
    1246                 :             :     }
    1247                 :             : 
    1248                 :         908 :     PERR ("Account \"%s\" does not have a commodity!",
    1249                 :             :           xaccAccountGetName(account));
    1250                 :             : }
    1251                 :             : 
    1252                 :             : /* ================================================================ */
    1253                 :             : 
    1254                 :             : /* EFFECTIVE FRIEND FUNCTION declared in qofinstance-p.h */
    1255                 :             : extern void qof_instance_set_dirty (QofInstance*);
    1256                 :             : 
    1257                 :             : static void
    1258                 :         451 : xaccAccountDeleteOldData (Account *account)
    1259                 :             : {
    1260                 :         451 :     if (!account) return;
    1261                 :         451 :     xaccAccountBeginEdit (account);
    1262                 :         451 :     qof_instance_set_kvp (QOF_INSTANCE (account), nullptr, 1, "old-currency");
    1263                 :         451 :     qof_instance_set_kvp (QOF_INSTANCE (account), nullptr, 1, "old-security");
    1264                 :         451 :     qof_instance_set_kvp (QOF_INSTANCE (account), nullptr, 1, "old-currency-scu");
    1265                 :         451 :     qof_instance_set_kvp (QOF_INSTANCE (account), nullptr, 1, "old-security-scu");
    1266                 :         451 :     qof_instance_set_dirty (QOF_INSTANCE (account));
    1267                 :         451 :     xaccAccountCommitEdit (account);
    1268                 :             : }
    1269                 :             : 
    1270                 :             : static int
    1271                 :         768 : scrub_trans_currency_helper (Transaction *t, gpointer data)
    1272                 :             : {
    1273                 :         768 :     xaccTransScrubCurrency (t);
    1274                 :         768 :     return 0;
    1275                 :             : }
    1276                 :             : 
    1277                 :             : static void
    1278                 :         451 : scrub_account_commodity_helper (Account *account, gpointer data)
    1279                 :             : {
    1280                 :         451 :     scrub_depth++;
    1281                 :         451 :     xaccAccountScrubCommodity (account);
    1282                 :         451 :     xaccAccountDeleteOldData (account);
    1283                 :         451 :     scrub_depth--;
    1284                 :         451 : }
    1285                 :             : 
    1286                 :             : void
    1287                 :          21 : xaccAccountTreeScrubCommodities (Account *acc)
    1288                 :             : {
    1289                 :          21 :     if (!acc) return;
    1290                 :          21 :     scrub_depth++;
    1291                 :          21 :     xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, nullptr);
    1292                 :             : 
    1293                 :          21 :     scrub_account_commodity_helper (acc, nullptr);
    1294                 :          21 :     gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, nullptr);
    1295                 :          21 :     scrub_depth--;
    1296                 :             : }
    1297                 :             : 
    1298                 :             : /* ================================================================ */
    1299                 :             : 
    1300                 :             : static gboolean
    1301                 :        4852 : check_quote_source (gnc_commodity *com, gpointer data)
    1302                 :             : {
    1303                 :        4852 :     gboolean *commodity_has_quote_src = (gboolean *)data;
    1304                 :        4852 :     if (com && !gnc_commodity_is_iso(com))
    1305                 :          85 :         *commodity_has_quote_src |= gnc_commodity_get_quote_flag(com);
    1306                 :        4852 :     return TRUE;
    1307                 :             : }
    1308                 :             : 
    1309                 :             : static void
    1310                 :         451 : move_quote_source (Account *account, gpointer data)
    1311                 :             : {
    1312                 :             :     gnc_commodity *com;
    1313                 :             :     gnc_quote_source *quote_source;
    1314                 :         451 :     gboolean new_style = GPOINTER_TO_INT(data);
    1315                 :             :     const char *source, *tz;
    1316                 :             : 
    1317                 :         451 :     com = xaccAccountGetCommodity(account);
    1318                 :         451 :     if (!com)
    1319                 :          18 :         return;
    1320                 :             : 
    1321                 :         433 :     if (!new_style)
    1322                 :             :     {
    1323                 :         420 :         source = dxaccAccountGetPriceSrc(account);
    1324                 :         420 :         if (!source || !*source)
    1325                 :         420 :             return;
    1326                 :           0 :         tz = dxaccAccountGetQuoteTZ(account);
    1327                 :             : 
    1328                 :           0 :         PINFO("to %8s from %s", gnc_commodity_get_mnemonic(com),
    1329                 :             :               xaccAccountGetName(account));
    1330                 :           0 :         gnc_commodity_set_quote_flag(com, TRUE);
    1331                 :           0 :         quote_source = gnc_quote_source_lookup_by_internal(source);
    1332                 :           0 :         if (!quote_source)
    1333                 :           0 :             quote_source = gnc_quote_source_add_new(source, FALSE);
    1334                 :           0 :         gnc_commodity_set_quote_source(com, quote_source);
    1335                 :           0 :         gnc_commodity_set_quote_tz(com, tz);
    1336                 :             :     }
    1337                 :             : 
    1338                 :          13 :     dxaccAccountSetPriceSrc(account, nullptr);
    1339                 :          13 :     dxaccAccountSetQuoteTZ(account, nullptr);
    1340                 :          13 :     return;
    1341                 :             : }
    1342                 :             : 
    1343                 :             : 
    1344                 :             : void
    1345                 :          21 : xaccAccountTreeScrubQuoteSources (Account *root, gnc_commodity_table *table)
    1346                 :             : {
    1347                 :          21 :     gboolean new_style = FALSE;
    1348                 :          21 :     ENTER(" ");
    1349                 :             : 
    1350                 :          21 :     if (!root || !table)
    1351                 :             :     {
    1352                 :           0 :         LEAVE("Oops");
    1353                 :           0 :         return;
    1354                 :             :     }
    1355                 :          21 :     scrub_depth++;
    1356                 :          21 :     gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
    1357                 :             : 
    1358                 :          21 :     move_quote_source(root, GINT_TO_POINTER(new_style));
    1359                 :          21 :     gnc_account_foreach_descendant (root, move_quote_source,
    1360                 :          21 :                                     GINT_TO_POINTER(new_style));
    1361                 :          21 :     LEAVE("Migration done");
    1362                 :          21 :     scrub_depth--;
    1363                 :             : }
    1364                 :             : 
    1365                 :             : /* ================================================================ */
    1366                 :             : 
    1367                 :             : void
    1368                 :         450 : xaccAccountScrubKvp (Account *account)
    1369                 :             : {
    1370                 :         450 :     GValue v = G_VALUE_INIT;
    1371                 :             :     gchar *str2;
    1372                 :             : 
    1373                 :         450 :     if (!account) return;
    1374                 :         450 :     scrub_depth++;
    1375                 :             : 
    1376                 :         450 :     qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "notes");
    1377                 :         450 :     if (G_VALUE_HOLDS_STRING (&v))
    1378                 :             :     {
    1379                 :           1 :         str2 = g_strstrip(g_value_dup_string(&v));
    1380                 :           1 :         if (strlen(str2) == 0)
    1381                 :           0 :             qof_instance_slot_delete (QOF_INSTANCE (account), "notes");
    1382                 :           1 :         g_free(str2);
    1383                 :             :     }
    1384                 :             : 
    1385                 :         450 :     qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "placeholder");
    1386                 :         450 :     if ((G_VALUE_HOLDS_STRING (&v) &&
    1387                 :         900 :         strcmp(g_value_get_string (&v), "false") == 0) ||
    1388                 :         450 :         (G_VALUE_HOLDS_BOOLEAN (&v) && ! g_value_get_boolean (&v)))
    1389                 :           0 :         qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
    1390                 :             : 
    1391                 :         450 :     g_value_unset (&v);
    1392                 :         450 :     qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
    1393                 :         450 :     scrub_depth--;
    1394                 :             : }
    1395                 :             : 
    1396                 :             : /* ================================================================ */
    1397                 :             : 
    1398                 :             : void
    1399                 :           0 : xaccAccountScrubColorNotSet (QofBook *book)
    1400                 :             : {
    1401                 :           0 :     GValue value_s = G_VALUE_INIT;
    1402                 :             :     gboolean already_scrubbed;
    1403                 :             : 
    1404                 :             :     // get the run-once value
    1405                 :           0 :     qof_instance_get_kvp (QOF_INSTANCE (book), &value_s, 1, "remove-color-not-set-slots");
    1406                 :             : 
    1407                 :           0 :     already_scrubbed = (G_VALUE_HOLDS_STRING (&value_s) &&
    1408                 :           0 :                         !g_strcmp0 (g_value_get_string (&value_s), "true"));
    1409                 :           0 :     g_value_unset (&value_s);
    1410                 :             : 
    1411                 :           0 :     if (already_scrubbed)
    1412                 :           0 :         return;
    1413                 :             :     else
    1414                 :             :     {
    1415                 :           0 :         GValue value_b = G_VALUE_INIT;
    1416                 :           0 :         Account *root = gnc_book_get_root_account (book);
    1417                 :           0 :         GList *accts = gnc_account_get_descendants_sorted (root);
    1418                 :             :         GList *ptr;
    1419                 :             : 
    1420                 :           0 :         for (ptr = accts; ptr; ptr = g_list_next (ptr))
    1421                 :             :         {
    1422                 :           0 :             auto acct = GNC_ACCOUNT(ptr->data);
    1423                 :           0 :             auto color = xaccAccountGetColor (acct);
    1424                 :             : 
    1425                 :           0 :             if (g_strcmp0 (color, "Not Set") == 0)
    1426                 :           0 :                 xaccAccountSetColor (acct, "");
    1427                 :             :         }
    1428                 :           0 :         g_list_free (accts);
    1429                 :             : 
    1430                 :           0 :         g_value_init (&value_b, G_TYPE_BOOLEAN);
    1431                 :           0 :         g_value_set_boolean (&value_b, TRUE);
    1432                 :             : 
    1433                 :             :         // set the run-once value
    1434                 :           0 :         qof_instance_set_kvp (QOF_INSTANCE (book),  &value_b, 1, "remove-color-not-set-slots");
    1435                 :           0 :         g_value_unset (&value_b);
    1436                 :             :     }
    1437                 :             : }
    1438                 :             : 
    1439                 :             : /* ================================================================ */
    1440                 :             : 
    1441                 :             : static Account*
    1442                 :          79 : construct_account (Account *root, gnc_commodity *currency, const char *accname,
    1443                 :             :                    GNCAccountType acctype, gboolean placeholder)
    1444                 :             : {
    1445                 :          79 :     gnc_commodity* root_currency = find_root_currency ();
    1446                 :          79 :     Account *acc = xaccMallocAccount(gnc_account_get_book (root));
    1447                 :          79 :     xaccAccountBeginEdit (acc);
    1448                 :          79 :     if (accname && *accname)
    1449                 :          79 :          xaccAccountSetName (acc, accname);
    1450                 :          79 :     if (currency || root_currency)
    1451                 :          79 :          xaccAccountSetCommodity (acc, currency ? currency : root_currency);
    1452                 :          79 :     xaccAccountSetType (acc, acctype);
    1453                 :          79 :     xaccAccountSetPlaceholder (acc, placeholder);
    1454                 :             : 
    1455                 :             :     /* Hang the account off the root. */
    1456                 :          79 :     gnc_account_append_child (root, acc);
    1457                 :          79 :     xaccAccountCommitEdit (acc);
    1458                 :          79 :     return acc;
    1459                 :             : }
    1460                 :             : 
    1461                 :             : static Account*
    1462                 :           0 : find_root_currency_account_in_list (GList *acc_list)
    1463                 :             : {
    1464                 :           0 :     gnc_commodity* root_currency = find_root_currency();
    1465                 :           0 :     for (GList *node = acc_list; node; node = g_list_next (node))
    1466                 :             :     {
    1467                 :           0 :         Account *acc = GNC_ACCOUNT (node->data);
    1468                 :           0 :         gnc_commodity *acc_commodity = nullptr;
    1469                 :           0 :         if (G_UNLIKELY (!acc)) continue;
    1470                 :           0 :         acc_commodity = xaccAccountGetCommodity(acc);
    1471                 :           0 :         if (gnc_commodity_equiv (acc_commodity, root_currency))
    1472                 :           0 :             return acc;
    1473                 :             :     }
    1474                 :             : 
    1475                 :           0 :     return nullptr;
    1476                 :             : }
    1477                 :             : 
    1478                 :             : static Account*
    1479                 :           0 : find_account_matching_name_in_list (GList *acc_list, const char* accname)
    1480                 :             : {
    1481                 :           0 :     for (GList* node = acc_list; node; node = g_list_next(node))
    1482                 :             :     {
    1483                 :           0 :         Account *acc = GNC_ACCOUNT (node->data);
    1484                 :           0 :         if (G_UNLIKELY (!acc)) continue;
    1485                 :           0 :         if (g_strcmp0 (accname, xaccAccountGetName (acc)) == 0)
    1486                 :           0 :             return acc;
    1487                 :             :     }
    1488                 :           0 :     return nullptr;
    1489                 :             : }
    1490                 :             : 
    1491                 :             : Account *
    1492                 :          95 : xaccScrubUtilityGetOrMakeAccount (Account *root, gnc_commodity * currency,
    1493                 :             :                                   const char *accname, GNCAccountType acctype,
    1494                 :             :                                   gboolean placeholder, gboolean checkname)
    1495                 :             : {
    1496                 :             :     GList* acc_list;
    1497                 :          95 :     Account *acc = nullptr;
    1498                 :             : 
    1499                 :          95 :     g_return_val_if_fail (root, nullptr);
    1500                 :             : 
    1501                 :             :     acc_list =
    1502                 :          95 :         gnc_account_lookup_by_type_and_commodity (root,
    1503                 :             :                                                   checkname ? accname : nullptr,
    1504                 :             :                                                   acctype, currency);
    1505                 :             : 
    1506                 :          95 :     if (!acc_list)
    1507                 :          79 :         return construct_account (root, currency, accname,
    1508                 :          79 :                                   acctype, placeholder);
    1509                 :             : 
    1510                 :          16 :     if (g_list_next(acc_list))
    1511                 :             :     {
    1512                 :           0 :         if (!currency)
    1513                 :           0 :             acc = find_root_currency_account_in_list (acc_list);
    1514                 :             : 
    1515                 :           0 :         if (!acc)
    1516                 :           0 :             acc = find_account_matching_name_in_list (acc_list, accname);
    1517                 :             :     }
    1518                 :             : 
    1519                 :          16 :     if (!acc)
    1520                 :          16 :         acc = GNC_ACCOUNT (acc_list->data);
    1521                 :             : 
    1522                 :          16 :     g_list_free (acc_list);
    1523                 :          16 :     return acc;
    1524                 :             : }
    1525                 :             : 
    1526                 :             : void
    1527                 :         782 : xaccTransScrubPostedDate (Transaction *trans)
    1528                 :             : {
    1529                 :         782 :     time64 orig = xaccTransGetDate(trans);
    1530                 :         782 :     if(orig == INT64_MAX)
    1531                 :             :     {
    1532                 :           0 :         GDate date = xaccTransGetDatePostedGDate(trans);
    1533                 :           0 :         time64 time = gdate_to_time64(date);
    1534                 :           0 :         if(time != INT64_MAX)
    1535                 :             :         {
    1536                 :             :             // xaccTransSetDatePostedSecs handles committing the change.
    1537                 :           0 :             xaccTransSetDatePostedSecs(trans, time);
    1538                 :             :         }
    1539                 :             :     }
    1540                 :         782 : }
    1541                 :             : 
    1542                 :             : /* ==================== END OF FILE ==================== */
        

Generated by: LCOV version 2.0-1