LCOV - code coverage report
Current view: top level - libgnucash/engine - Scrub3.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 89.8 % 59 53
Test Date: 2025-02-07 16:25:45 Functions: 100.0 % 5 5
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************\
       2                 :             :  * Scrub3.c -- Constrain Cap Gains to Track Sources of Gains        *
       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                 :             : /** @file Scrub3.c
      23                 :             :  *  @brief Constrain Cap Gains to Track Sources of Gains
      24                 :             :  *  @author Created by Linas Vepstas Sept 2003
      25                 :             :  *  @author Copyright (c) 2003,2004 Linas Vepstas <linas@linas.org>
      26                 :             :  *
      27                 :             :  * Provides a set of functions and utilities for checking and
      28                 :             :  * repairing ('scrubbing clean') the usage of Cap Gains
      29                 :             :  * transactions in stock and commodity accounts.
      30                 :             :  */
      31                 :             : 
      32                 :             : #include <config.h>
      33                 :             : 
      34                 :             : #include <glib.h>
      35                 :             : 
      36                 :             : #include "cap-gains.h"
      37                 :             : #include "gnc-commodity.h"
      38                 :             : #include "gnc-engine.h"
      39                 :             : #include "gnc-lot.h"
      40                 :             : #include "policy-p.h"
      41                 :             : #include "Account.h"
      42                 :             : #include "AccountP.hpp"
      43                 :             : #include "Scrub2.h"
      44                 :             : #include "Scrub3.h"
      45                 :             : #include "Transaction.h"
      46                 :             : #include "TransactionP.hpp"
      47                 :             : 
      48                 :             : static QofLogModule log_module = GNC_MOD_LOT;
      49                 :             : 
      50                 :             : /* ================================================================= */
      51                 :             : /** Cap gains are possible only if the lot commodity is not the same
      52                 :             :  * as the transaction currency.  We assume here that all splits in
      53                 :             :  * the lot share the same transaction currency, and so we look at
      54                 :             :  * the first split, and see what it's currency is.
      55                 :             :  * This routine returns TRUE if cap gains are possible.
      56                 :             :  */
      57                 :             : 
      58                 :             : static inline gboolean
      59                 :          53 : gains_possible (GNCLot *lot)
      60                 :             : {
      61                 :             :     SplitList *node;
      62                 :             :     Account *acc;
      63                 :             :     Split *split;
      64                 :             :     gboolean comeq;
      65                 :             :     gnc_commodity *acc_commodity;
      66                 :             : 
      67                 :          53 :     acc = gnc_lot_get_account (lot);
      68                 :             : 
      69                 :          53 :     node = gnc_lot_get_split_list (lot);
      70                 :          53 :     if (!node) return FALSE;
      71                 :          53 :     split = GNC_SPLIT(node->data);
      72                 :             : 
      73                 :          53 :     acc_commodity = xaccAccountGetCommodity(acc);
      74                 :          53 :     comeq = gnc_commodity_equiv (acc_commodity, split->parent->common_currency);
      75                 :          53 :     return (FALSE == comeq);
      76                 :             : }
      77                 :             : 
      78                 :             : /* ================================================================= */
      79                 :             : /* XXX What happens if, as a result of scrubbing, the lot is empty?
      80                 :             :  * I don't think this is handled properly.  I think that what will
      81                 :             :  * happen is we'll end up with an empty, closed lot ... ?
      82                 :             :  */
      83                 :             : 
      84                 :             : gboolean
      85                 :          53 : xaccScrubLot (GNCLot *lot)
      86                 :             : {
      87                 :          53 :     gboolean splits_deleted = FALSE;
      88                 :             :     gnc_numeric lot_baln;
      89                 :             :     gboolean opening_baln_is_pos, lot_baln_is_pos;
      90                 :             :     Account *acc;
      91                 :             :     GNCPolicy *pcy;
      92                 :             : 
      93                 :          53 :     if (!lot) return FALSE;
      94                 :          53 :     ENTER ("(lot=%p) %s", lot, gnc_lot_get_title(lot));
      95                 :             : 
      96                 :          53 :     acc = gnc_lot_get_account (lot);
      97                 :          53 :     pcy = gnc_account_get_policy(acc);
      98                 :          53 :     xaccAccountBeginEdit(acc);
      99                 :          53 :     xaccScrubMergeLotSubSplits (lot, TRUE);
     100                 :             : 
     101                 :             :     /* If the lot balance is zero, we don't need to rebalance */
     102                 :          53 :     lot_baln = gnc_lot_get_balance (lot);
     103                 :          53 :     PINFO ("lot baln=%s for %s", gnc_num_dbg_to_string (lot_baln),
     104                 :             :            gnc_lot_get_title(lot));
     105                 :          53 :     if (! gnc_numeric_zero_p (lot_baln))
     106                 :             :     {
     107                 :             :         SplitList *node;
     108                 :             :         gnc_numeric opening_baln;
     109                 :             : 
     110                 :             :         /* Get the opening balance for this lot */
     111                 :          48 :         pcy->PolicyGetLotOpening (pcy, lot, &opening_baln, nullptr, nullptr);
     112                 :          48 :         PINFO ("lot opener baln=%s", gnc_num_dbg_to_string (opening_baln));
     113                 :             : 
     114                 :             :         /* If the lot is fat, give the boot to all the non-opening
     115                 :             :          * splits, and refill it */
     116                 :          48 :         opening_baln_is_pos = gnc_numeric_positive_p(opening_baln);
     117                 :          48 :         lot_baln_is_pos = gnc_numeric_positive_p(lot_baln);
     118                 :          48 :         if ((opening_baln_is_pos || lot_baln_is_pos) &&
     119                 :          21 :                 ((!opening_baln_is_pos) || (!lot_baln_is_pos)))
     120                 :             :         {
     121                 :           0 : rethin:
     122                 :           0 :             for (node = gnc_lot_get_split_list(lot); node; node = node->next)
     123                 :             :             {
     124                 :           0 :                 Split *s = GNC_SPLIT(node->data);
     125                 :           0 :                 if (pcy->PolicyIsOpeningSplit (pcy, lot, s)) continue;
     126                 :           0 :                 gnc_lot_remove_split (lot, s);
     127                 :           0 :                 goto rethin;
     128                 :             :             }
     129                 :             :         }
     130                 :             : 
     131                 :             :         /* At this point the lot is thin, so try to fill it */
     132                 :          48 :         xaccLotFill (lot);
     133                 :             : 
     134                 :             :         /* Make sure there are no subsplits. */
     135                 :          48 :         splits_deleted = xaccScrubMergeLotSubSplits (lot, TRUE);
     136                 :             :     }
     137                 :             : 
     138                 :             :     /* Now re-compute cap gains, and then double-check that.
     139                 :             :      * But we only compute cap-gains if gains are possible;
     140                 :             :      * that is if the lot commodity is not the same as the
     141                 :             :      * currency. That is, one can't possibly have gains
     142                 :             :      * selling dollars for dollars.  The business modules
     143                 :             :      * use lots with lot commodity == lot currency.
     144                 :             :      */
     145                 :          53 :     if (gains_possible (lot))
     146                 :             :     {
     147                 :          52 :         xaccLotComputeCapGains (lot, nullptr);
     148                 :          52 :         xaccLotScrubDoubleBalance (lot);
     149                 :             :     }
     150                 :          53 :     xaccAccountCommitEdit(acc);
     151                 :             : 
     152                 :          53 :     LEAVE ("(lot=%s, deleted=%d)", gnc_lot_get_title(lot), splits_deleted);
     153                 :          53 :     return splits_deleted;
     154                 :             : }
     155                 :             : 
     156                 :             : /* ============================================================== */
     157                 :             : 
     158                 :             : void
     159                 :           4 : xaccAccountScrubLots (Account *acc)
     160                 :             : {
     161                 :             :     LotList *lots, *node;
     162                 :           4 :     if (!acc) return;
     163                 :           4 :     if (FALSE == xaccAccountHasTrades (acc)) return;
     164                 :             : 
     165                 :           3 :     ENTER ("(acc=%s)", xaccAccountGetName(acc));
     166                 :           3 :     xaccAccountBeginEdit(acc);
     167                 :           3 :     xaccAccountAssignLots (acc);
     168                 :             : 
     169                 :           3 :     lots = xaccAccountGetLotList(acc);
     170                 :          56 :     for (node = lots; node; node = node->next)
     171                 :             :     {
     172                 :          53 :         GNCLot *lot = GNC_LOT(node->data);
     173                 :          53 :         xaccScrubLot (lot);
     174                 :             :     }
     175                 :           3 :     g_list_free(lots);
     176                 :           3 :     xaccAccountCommitEdit(acc);
     177                 :           3 :     LEAVE ("(acc=%s)", xaccAccountGetName(acc));
     178                 :             : }
     179                 :             : 
     180                 :             : /* ============================================================== */
     181                 :             : 
     182                 :             : static void
     183                 :           4 : lot_scrub_cb (Account *acc, gpointer data)
     184                 :             : {
     185                 :           4 :     if (FALSE == xaccAccountHasTrades (acc)) return;
     186                 :           2 :     xaccAccountScrubLots (acc);
     187                 :             : }
     188                 :             : 
     189                 :             : void
     190                 :           1 : xaccAccountTreeScrubLots (Account *acc)
     191                 :             : {
     192                 :           1 :     if (!acc) return;
     193                 :             : 
     194                 :           1 :     gnc_account_foreach_descendant(acc, lot_scrub_cb, nullptr);
     195                 :           1 :     xaccAccountScrubLots (acc);
     196                 :             : }
     197                 :             : 
     198                 :             : /* ========================== END OF FILE  ========================= */
        

Generated by: LCOV version 2.0-1