GnuCash  2.6.99
Files

Data scrubbing, repairing and forward migration routines. More...

Files

file  Scrub.h
 convert single-entry accounts to clean double-entry
 
file  Scrub2.h
 Utilities to Convert Stock Accounts to use Lots.
 
file  Scrub3.h
 High-Level API for imposing Lot constraints.
 
file  ScrubBusiness.h
 Cleanup functions for business objects.
 

Double-Entry Scrubbing

Convert single-entry accounts to clean double-entry

Provides a set of functions and utilities for checking and repairing (formerly called 'scrubbing clean') single-entry accounts so that they can be promoted into self-consistent, clean double-entry accounts. Basically and additionally, this file collects all functions that turn old (deprecated) data structures into the current new data model.

The ScrubOrphans() methods search for transacations that contain splits that do not have a parent account. These "orphaned splits" are placed into an "orphan account" which the user will have to go into and clean up. Kind of like the unix "Lost+Found" directory for orphaned inodes.

void xaccTransScrubOrphans (Transaction *trans)
 The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.
 
void xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
 The xaccAccountScrubOrphans() method performs this scrub only for the indicated account, and not for any of its children.
 
void xaccAccountTreeScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
 The xaccAccountTreeScrubOrphans() method performs this scrub for the indicated account and its children.
 
void xaccSplitScrub (Split *split)
 The xaccSplitScrub method ensures that if this split has the same commodity and currency, then it will have the same amount and value. More...
 
void xaccTransScrubSplits (Transaction *trans)
 The xacc*ScrubSplits() calls xaccSplitScrub() on each split in the respective structure: transaction, account, account & it's children, account-group.
 
void xaccAccountScrubSplits (Account *account)
 
void xaccAccountTreeScrubSplits (Account *account)
 
void xaccTransScrubImbalance (Transaction *trans, Account *root, Account *parent)
 The xaccScrubImbalance() method searches for transactions that do not balance to zero. More...
 
void xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
 
void xaccAccountTreeScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
 
void xaccTransScrubCurrency (Transaction *trans)
 The xaccTransScrubCurrency method fixes transactions without a common_currency by looking for the most commonly used currency among all the splits in the transaction. More...
 
void xaccAccountScrubCommodity (Account *account)
 The xaccAccountScrubCommodity method fixed accounts without a commodity by using the old account currency and security. More...
 
void xaccAccountTreeScrubCommodities (Account *acc)
 The xaccAccountTreeScrubCommodities will scrub the currency/commodity of all accounts & transactions in the specified account or any child account. More...
 
void xaccAccountTreeScrubQuoteSources (Account *root, gnc_commodity_table *table)
 This routine will migrate the information about price quote sources from the account data structures to the commodity data structures. More...
 
void xaccAccountScrubKvp (Account *account)
 Removes empty "notes", "placeholder", and "hbci" KVP slots from Accounts. More...
 
void xaccTransScrubPostedDate (Transaction *trans)
 Changes Transaction date_posted timestamps from 00:00 local to 11:00 UTC. More...
 

Lot Management Routines

Provides the low-level API for checking and repairing ('scrubbing clean') the usage of Lots and lot balances in stock and commodity accounts.

Broken lots are repaired using a first-in, first-out (FIFO) accounting schedule.

This is a 'low-level' API in the sense that each routine accomplishes only one particular task needed to clean up a Lot. To clean up a Lot as a whole, you almost certainly want to use one of the high-level API routines from the Scrub3.h file.

void xaccAccountAssignLots (Account *acc)
 The xaccAccountAssignLots() routine will walk over all of the splits in an account, and make sure that each belongs to a lot. More...
 
void xaccLotFill (GNCLot *lot)
 The xaccLotFill() routine attempts to assign splits to the indicated lot until the lot balance goes to zero, or until there are no suitable (i.e. More...
 
void xaccLotScrubDoubleBalance (GNCLot *lot)
 The xaccLotScrubDoubleBalance() routine examines the indicated lot. More...
 
gboolean xaccScrubMergeSubSplits (Split *split, gboolean strict)
 The xaccScrubMergeSubSplits() routine will merge together all of the splits that were at one time split off from this split, but are no longer needed to be kept separate. More...
 
gboolean xaccScrubMergeLotSubSplits (GNCLot *lot, gboolean strict)
 The xaccScrubMergeLotSubSplits() routine does the same as the xaccScrubMergSubSplits, except that it does it for all of the splits in the lot.
 

High-Level Lot Constraint

Provides the high-level API for checking and repairing ('scrubbing clean') the usage of Lots and Cap Gains transactions in stock and commodity accounts.

gboolean xaccScrubLot (GNCLot *lot)
 The xaccScrubLot() routine makes sure that the indicated lot is self-consistent and properly balanced, and fixes it if its not. More...
 
void xaccAccountScrubLots (Account *acc)
 The xaccAccountScrubLots() routine makes sure that every split in the account is assigned to a lot, and that then, every lot is self-consistent (by calling xaccScrubLot() on each lot). More...
 
void xaccAccountTreeScrubLots (Account *acc)
 

Cleanup functions for business objects

Provides the high-level API for checking and repairing ('scrubbing clean') the various data objects used by the business functions.

gboolean gncScrubBusinessLot (GNCLot *lot)
 The gncScrubBusinessLot() function makes sure that the indicated lot has all the correct properties required for a lot used in the business features. More...
 
gboolean gncScrubBusinessSplit (Split *split)
 The gncScrubBusinessSplit() function will fix all issues found with the given split. More...
 
void gncScrubBusinessAccountLots (Account *acc, QofPercentageFunc percentagefunc)
 The gncScrubBusinessAccountLots() function will call gncScrubBusinessLot() on each lot in the given account. More...
 
void gncScrubBusinessAccountSplits (Account *acc, QofPercentageFunc percentagefunc)
 The gncScrubBusinessAccountSplits() function will call gncScrubBusinessSplit() on each split in the given account.
 
void gncScrubBusinessAccount (Account *acc, QofPercentageFunc percentagefunc)
 The gncScrubBusinessAccount() function will call all scrub functions relevant for a given account on condition the account is a business related account (Accounts Receivable or Accounts Payable type). More...
 
void gncScrubBusinessAccountTree (Account *acc, QofPercentageFunc percentagefunc)
 The gncScrubBusinessAccountTreeLots() function will call gncScrubBusinessAccount() on the given account and its sub accounts.
 

Detailed Description

Data scrubbing, repairing and forward migration routines.

These routines check and repair data, making sure that it is in a format that the current version of the GnuCash Engine likes. These routines serve both to provide backwards compatibility with older versions of GnuCash, and to fix or at least paper over possible current problems.

It is typically expected that the scrub routines are run over newly imported data, as well as during data file input.

In some cases, it is entirely appropriate to invoke these routines from the GUI, to validate that the user input through the GUI is in a format that the system likes. This includes things like balancing individual transactions, or assigning splits to lots, so that capital gains can be computed.

Function Documentation

◆ gncScrubBusinessAccount()

void gncScrubBusinessAccount ( Account acc,
QofPercentageFunc  percentagefunc 
)

The gncScrubBusinessAccount() function will call all scrub functions relevant for a given account on condition the account is a business related account (Accounts Receivable or Accounts Payable type).

This routine is the primary routine for fixing all (known) issues in a business account.

Definition at line 690 of file ScrubBusiness.c.

691 {
692  if (!acc) return;
693  if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
694 
695  gncScrubBusinessAccountLots (acc, percentagefunc);
696  gncScrubBusinessAccountSplits (acc, percentagefunc);
697 }
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition: Account.c:3010
void gncScrubBusinessAccountSplits(Account *acc, QofPercentageFunc percentagefunc)
The gncScrubBusinessAccountSplits() function will call gncScrubBusinessSplit() on each split in the g...
void gncScrubBusinessAccountLots(Account *acc, QofPercentageFunc percentagefunc)
The gncScrubBusinessAccountLots() function will call gncScrubBusinessLot() on each lot in the given a...
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.c:4228

◆ gncScrubBusinessAccountLots()

void gncScrubBusinessAccountLots ( Account acc,
QofPercentageFunc  percentagefunc 
)

The gncScrubBusinessAccountLots() function will call gncScrubBusinessLot() on each lot in the given account.

This routine is the primary routine for ensuring that the lot structure of every lot of a business account is in good order.

Definition at line 586 of file ScrubBusiness.c.

587 {
588  LotList *lots, *node;
589  gint lot_count = 0;
590  gint curr_lot_no = 0;
591  const gchar *str;
592  const char *message = _( "Checking business lots in account %s: %u of %u");
593 
594  if (!acc) return;
595  if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
596 
597  str = xaccAccountGetName(acc);
598  str = str ? str : "(null)";
599 
600  ENTER ("(acc=%s)", str);
601  PINFO ("Cleaning up superfluous lot links in account %s \n", str);
603 
604  lots = xaccAccountGetLotList(acc);
605  lot_count = g_list_length (lots);
606  for (node = lots; node; node = node->next)
607  {
608  GNCLot *lot = node->data;
609 
610  PINFO("Start processing lot %d of %d",
611  curr_lot_no + 1, lot_count);
612 
613  if (curr_lot_no % 100 == 0)
614  {
615  char *progress_msg = g_strdup_printf (message, str, curr_lot_no, lot_count);
616  (percentagefunc)(progress_msg, (100 * curr_lot_no) / lot_count);
617  g_free (progress_msg);
618  }
619 
620  if (lot)
621  gncScrubBusinessLot (lot);
622 
623  PINFO("Finished processing lot %d of %d",
624  curr_lot_no + 1, lot_count);
625  curr_lot_no++;
626  }
627  g_list_free(lots);
629  (percentagefunc)(NULL, -1.0);
630  LEAVE ("(acc=%s)", str);
631 }
GList LotList
GList of GNCLots.
Definition: gnc-engine.h:201
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:249
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition: Account.c:3010
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition: Account.c:3751
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.c:4228
gboolean gncScrubBusinessLot(GNCLot *lot)
The gncScrubBusinessLot() function makes sure that the indicated lot has all the correct properties r...
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.c:1295
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.c:3032
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.c:1336

◆ gncScrubBusinessLot()

gboolean gncScrubBusinessLot ( GNCLot *  lot)

The gncScrubBusinessLot() function makes sure that the indicated lot has all the correct properties required for a lot used in the business features.

Currently this function only does one thing: eliminate lot link transactions between invoice lots and payment lots (which were generated by GnuCash versions 2.6.0-2.6.3). Lot links between invoices and credit notes will still remain.

Scrubbing the lot may cause subsplits to be merged together, i.e. for splits to be deleted. This routine returns true if any splits were modified or deleted.

Definition at line 458 of file ScrubBusiness.c.

459 {
460  gboolean splits_deleted = FALSE;
461  gboolean dangling_payments = FALSE;
462  gboolean dangling_lot_link = FALSE;
463  Account *acc;
464  gchar *lotname=NULL;
465 
466  if (!lot) return FALSE;
467  lotname = g_strdup (gnc_lot_get_title (lot));
468  ENTER ("(lot=%p) %s", lot, lotname ? lotname : "(no lotname)");
469 
470  acc = gnc_lot_get_account (lot);
471  if (acc)
473 
474  /* Check invoice link consistency
475  * A lot should have both or neither of:
476  * - one split from an invoice transaction
477  * - an invoice-guid set
478  */
479  gncScrubInvoiceState (lot);
480 
481  // Scrub lot links.
482  // They should only remain when two document lots are linked together
483  xaccScrubMergeLotSubSplits (lot, FALSE);
484  splits_deleted = gncScrubLotLinks (lot);
485 
486  // Look for dangling payments and repair if found
487  dangling_lot_link = gncScrubLotIsSingleLotLinkSplit (lot);
488  if (dangling_lot_link)
489  {
490  dangling_payments = gncScrubLotDanglingPayments (lot);
491  if (dangling_payments)
492  splits_deleted |= gncScrubLotLinks (lot);
493  else
494  {
495  Split *split = gnc_lot_get_earliest_split (lot);
496  Transaction *trans = xaccSplitGetParent (split);
497  xaccTransDestroy (trans);
498  }
499  }
500 
501  // If lot is empty now, delete it
502  if (0 == gnc_lot_count_splits (lot))
503  {
504  PINFO("All splits were removed from lot, deleting");
505  gnc_lot_destroy (lot);
506  }
507 
508  if (acc)
510 
511  LEAVE ("(lot=%s, deleted=%d, dangling lot link=%d, dangling_payments=%d)",
512  lotname ? lotname : "(no lotname)", splits_deleted, dangling_lot_link,
513  dangling_payments);
514  g_free (lotname);
515 
516  return splits_deleted;
517 }
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
The xaccScrubMergeLotSubSplits() routine does the same as the xaccScrubMergSubSplits, except that it does it for all of the splits in the lot.
Definition: Scrub2.c:384
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:249
STRUCTS.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition: Split.c:1845
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
Split * gnc_lot_get_earliest_split(GNCLot *lot)
The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the date this l...
Definition: gnc-lot.c:659
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.c:438
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Definition: Transaction.c:1465
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.c:1295
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.c:387
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.c:1336

◆ gncScrubBusinessSplit()

gboolean gncScrubBusinessSplit ( Split *  split)

The gncScrubBusinessSplit() function will fix all issues found with the given split.

Current checks are:

  • check if the split is part of a transaction that was generated as the result of a doubly posted invoice/bill/credit note. Refer to https://bugzilla.gnome.org/show_bug.cgi?id=754209 to learn how this could have happened in the past. If such a transaction is found, its read-only status is removed and a warning is written to the trace file. Considering the user may already have added a correcting transaction we leave it up to the user to decide whether to also delete the transaction or not.
  • remove empty splits, on condition they aren't part of an invoice transaction. In this case the function returns true so the caller knows a split was removed.

Definition at line 520 of file ScrubBusiness.c.

521 {
522  const gchar *memo = _("Please delete this transaction. Explanation at http://wiki.gnucash.org/wiki/Business_Features_Issues#Double_Posting");
523  Transaction *txn;
524  gboolean deleted_split = FALSE;
525 
526  if (!split) return FALSE;
527  ENTER ("(split=%p)", split);
528 
529  txn = xaccSplitGetParent (split);
530  if (txn)
531  {
532  gchar txntype = xaccTransGetTxnType (txn);
533  const gchar *read_only = xaccTransGetReadOnly (txn);
534  gboolean is_void = xaccTransGetVoidStatus (txn);
535  GNCLot *lot = xaccSplitGetLot (split);
536 
537  /* Look for transactions as a result of double posting an invoice or bill
538  * Refer to https://bugzilla.gnome.org/show_bug.cgi?id=754209
539  * to learn how this could have happened in the past.
540  * Characteristics of such transaction are:
541  * - read only
542  * - not voided (to ensure read only is set by the business functions)
543  * - transaction type is none (should be type invoice for proper post transactions)
544  * - assigned to a lot
545  */
546  if ((txntype == TXN_TYPE_NONE) && read_only && !is_void && lot)
547  {
548  gchar *txn_date = qof_print_date (xaccTransGetDateEntered (txn));
549  xaccTransClearReadOnly (txn);
550  xaccSplitSetMemo (split, memo);
551  gnc_lot_remove_split (lot, split);
552  PWARN("Cleared double post status of transaction \"%s\", dated %s. "
553  "Please delete transaction and verify balance.",
555  txn_date);
556  g_free (txn_date);
557  }
558  /* Next delete any empty splits that aren't part of an invoice transaction
559  * Such splits may be the result of scrubbing the business lots, which can
560  * merge splits together while reducing superfluous lot links
561  */
563  {
564  GNCLot *lot = xaccSplitGetLot (split);
565  time64 pdate = xaccTransGetDate (txn);
566  gchar *pdatestr = gnc_ctime (&pdate);
567  PINFO ("Destroying empty split %p from transaction %s (%s)", split, pdatestr, xaccTransGetDescription(txn));
568  xaccSplitDestroy (split);
569 
570  // Also delete the lot containing this split if it was the last split in that lot
571  if (lot && (gnc_lot_count_splits (lot) == 0))
572  gnc_lot_destroy (lot);
573 
574  deleted_split = TRUE;
575  }
576 
577  }
578 
579  LEAVE ("(split=%p)", split);
580  return deleted_split;
581 }
char xaccTransGetTxnType(const Transaction *trans)
Returns the Transaction Type.
Definition: Transaction.c:2405
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2322
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:249
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.c:1456
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition: Split.c:1845
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Given a transaction, find and return the Invoice.
Definition: gncInvoice.c:1208
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:243
char * qof_print_date(time64 t)
Convenience; calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:678
#define TXN_TYPE_NONE
No transaction type.
Definition: Transaction.h:119
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition: Split.c:1716
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Definition: Transaction.c:2280
const char * xaccTransGetReadOnly(const Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
Definition: Transaction.c:2421
time64 xaccTransGetDateEntered(const Transaction *trans)
Retrieve the date of when the transaction was entered.
Definition: Transaction.c:2329
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
Definition: Transaction.c:2650
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:83
char * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition: gnc-date.cpp:233
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn't be...
Definition: Split.c:1895
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Definition: Split.c:1929

◆ xaccAccountAssignLots()

void xaccAccountAssignLots ( Account acc)

The xaccAccountAssignLots() routine will walk over all of the splits in an account, and make sure that each belongs to a lot.

Currently, the default (and only implemented) assignment policy is a FIFO policy: Any splits that are not in a lot will be used to close the oldest open lot(s). If there are no open lots, a new lot will be started. By trying to close the oldest lots, this effectively implements a FIFO accounting policy.

The xaccAccountAssignLots() routine will walk over all of the splits in an account, and make sure that each belongs to a lot.

If a split does not belong to any lots, poke it into one.

Definition at line 59 of file Scrub2.c.

60 {
61  SplitList *splits, *node;
62 
63  if (!acc) return;
64 
65  ENTER ("acc=%s", xaccAccountGetName(acc));
67 
68 restart_loop:
69  splits = xaccAccountGetSplitList(acc);
70  for (node = splits; node; node = node->next)
71  {
72  Split * split = node->data;
73 
74  /* If already in lot, then no-op */
75  if (split->lot) continue;
76 
77  /* Skip voided transactions */
78  if (gnc_numeric_zero_p (split->amount) &&
79  xaccTransGetVoidStatus(split->parent)) continue;
80 
81  if (xaccSplitAssign (split)) goto restart_loop;
82  }
84  LEAVE ("acc=%s", xaccAccountGetName(acc));
85 }
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.c:3724
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
GList SplitList
GList of Split.
Definition: gnc-engine.h:203
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
Definition: Transaction.c:2650
gboolean xaccSplitAssign(Split *split)
The`xaccSplitAssign() routine will take the indicated split and, if it doesn't already belong to a lo...
Definition: cap-gains.c:430
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.c:1295
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.c:3032
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.c:1336

◆ xaccAccountScrubCommodity()

void xaccAccountScrubCommodity ( Account account)

The xaccAccountScrubCommodity method fixed accounts without a commodity by using the old account currency and security.

Definition at line 1197 of file Scrub.c.

1198 {
1199  gnc_commodity *commodity;
1200 
1201  if (!account) return;
1202  if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return;
1203 
1204  commodity = xaccAccountGetCommodity (account);
1205  if (commodity) return;
1206 
1207  /* Use the 'obsolete' routines to try to figure out what the
1208  * account commodity should have been. */
1209  commodity = xaccAccountGetCommodity (account);
1210  if (commodity)
1211  {
1212  xaccAccountSetCommodity (account, commodity);
1213  return;
1214  }
1215 
1216  commodity = DxaccAccountGetCurrency (account);
1217  if (commodity)
1218  {
1219  xaccAccountSetCommodity (account, commodity);
1220  return;
1221  }
1222 
1223  PERR ("Account \"%s\" does not have a commodity!",
1224  xaccAccountGetName(account));
1225 }
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition: Account.c:3137
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition: Account.c:3010
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:237
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.c:3155
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.c:3032
The hidden root account of an account tree.
Definition: Account.h:153
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account's commodity.
Definition: Account.c:2387

◆ xaccAccountScrubKvp()

void xaccAccountScrubKvp ( Account account)

Removes empty "notes", "placeholder", and "hbci" KVP slots from Accounts.

Definition at line 1339 of file Scrub.c.

1340 {
1341  GValue v = G_VALUE_INIT;
1342  const gchar *str;
1343  gchar *str2;
1344 
1345  if (!account) return;
1346 
1347  qof_instance_get_kvp (QOF_INSTANCE (account), "notes", &v);
1348  if (G_VALUE_HOLDS_STRING (&v))
1349  {
1350  str2 = g_strstrip(g_value_dup_string(&v));
1351  if (strlen(str2) == 0)
1352  qof_instance_slot_delete (QOF_INSTANCE (account), "notes");
1353  g_free(str2);
1354  }
1355 
1356  qof_instance_get_kvp (QOF_INSTANCE (account), "placeholder", &v);
1357  if ((G_VALUE_HOLDS_STRING (&v) &&
1358  strcmp(g_value_get_string (&v), "false") == 0) ||
1359  (G_VALUE_HOLDS_BOOLEAN (&v) && ! g_value_get_boolean (&v)))
1360  qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
1361 
1362  qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
1363 }
void qof_instance_get_kvp(const QofInstance *inst, const gchar *key, GValue *value)
Retrieves the contents of a KVP slot into a provided GValue.

◆ xaccAccountScrubLots()

void xaccAccountScrubLots ( Account acc)

The xaccAccountScrubLots() routine makes sure that every split in the account is assigned to a lot, and that then, every lot is self-consistent (by calling xaccScrubLot() on each lot).

This routine is the primary routine for ensuring that the lot structure, and the cap-gains for an account are in good order.

Most GUI routines will want to use one of these xacc[*]ScrubLots() routines, instead of the various component routines, since it will usually makes sense to work only with these high-level routines.

Definition at line 159 of file Scrub3.c.

160 {
161  LotList *lots, *node;
162  if (!acc) return;
163  if (FALSE == xaccAccountHasTrades (acc)) return;
164 
165  ENTER ("(acc=%s)", xaccAccountGetName(acc));
167  xaccAccountAssignLots (acc);
168 
169  lots = xaccAccountGetLotList(acc);
170  for (node = lots; node; node = node->next)
171  {
172  GNCLot *lot = node->data;
173  xaccScrubLot (lot);
174  }
175  g_list_free(lots);
177  LEAVE ("(acc=%s)", xaccAccountGetName(acc));
178 }
GList LotList
GList of GNCLots.
Definition: gnc-engine.h:201
gboolean xaccAccountHasTrades(const Account *acc)
The xaccAccountHasTrades() method checks to see if the indicated account is used in the trading of co...
Definition: cap-gains.c:79
void xaccAccountAssignLots(Account *acc)
Loop over all splits, and make sure that every split belongs to some lot.
Definition: Scrub2.c:59
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition: Account.c:3751
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.c:1295
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
gboolean xaccScrubLot(GNCLot *lot)
The xaccScrubLot() routine makes sure that the indicated lot is self-consistent and properly balanced...
Definition: Scrub3.c:85
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.c:3032
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.c:1336

◆ xaccAccountTreeScrubCommodities()

void xaccAccountTreeScrubCommodities ( Account acc)

The xaccAccountTreeScrubCommodities will scrub the currency/commodity of all accounts & transactions in the specified account or any child account.

Definition at line 1260 of file Scrub.c.

1261 {
1262  if (!acc) return;
1263 
1264  xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, NULL);
1265 
1266  scrub_account_commodity_helper (acc, NULL);
1267  gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, NULL);
1268 }
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
Traverse all of the transactions in the given account group.
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling 'func' on each...
Definition: Account.c:2959

◆ xaccAccountTreeScrubQuoteSources()

void xaccAccountTreeScrubQuoteSources ( Account root,
gnc_commodity_table *  table 
)

This routine will migrate the information about price quote sources from the account data structures to the commodity data structures.

It first checks to see if this is necessary since, for the time being, the quote information will still be written out as part of the account. Just in case anyone needs to fall back from CVS to a production version of code.

Parameters
rootA pointer to the root account containing all accounts in the current book.
tableA pointer to the commodity table for the current book.

Definition at line 1317 of file Scrub.c.

1318 {
1319  gboolean new_style = FALSE;
1320  ENTER(" ");
1321 
1322  if (!root || !table)
1323  {
1324  LEAVE("Oops");
1325  return;
1326  }
1327 
1328  gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
1329 
1330  move_quote_source(root, GINT_TO_POINTER(new_style));
1331  gnc_account_foreach_descendant (root, move_quote_source,
1332  GINT_TO_POINTER(new_style));
1333  LEAVE("Migration done");
1334 }
gboolean gnc_commodity_table_foreach_commodity(const gnc_commodity_table *table, gboolean(*f)(gnc_commodity *cm, gpointer user_data), gpointer user_data)
Call a function once for each commodity in the commodity table.
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling 'func' on each...
Definition: Account.c:2959
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271

◆ xaccLotFill()

void xaccLotFill ( GNCLot *  lot)

The xaccLotFill() routine attempts to assign splits to the indicated lot until the lot balance goes to zero, or until there are no suitable (i.e.

unassigned) splits left in the account. It uses the default accounting policy to choose the splits to fill out the lot.

Definition at line 97 of file Scrub2.c.

98 {
99  Account *acc;
100  Split *split;
101  GNCPolicy *pcy;
102 
103  if (!lot) return;
104  acc = gnc_lot_get_account(lot);
105  pcy = gnc_account_get_policy(acc);
106 
107  ENTER ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), xaccAccountGetName(acc));
108 
109  /* If balance already zero, we have nothing to do. */
110  if (gnc_lot_is_closed (lot))
111  {
112  LEAVE ("Lot Closed (lot=%s, acc=%s)", gnc_lot_get_title(lot),
113  xaccAccountGetName(acc));
114  return;
115  }
116  split = pcy->PolicyGetSplit (pcy, lot);
117  if (!split)
118  {
119  LEAVE ("No Split (lot=%s, acc=%s)", gnc_lot_get_title(lot),
120  xaccAccountGetName(acc));
121  return; /* Handle the common case */
122  }
123 
124  /* Reject voided transactions */
125  if (gnc_numeric_zero_p(split->amount) &&
126  xaccTransGetVoidStatus(split->parent))
127  {
128  LEAVE ("Voided transaction (lot=%s, acc=%s)",
130  return;
131  }
132 
133  xaccAccountBeginEdit (acc);
134 
135  /* Loop until we've filled up the lot, (i.e. till the
136  * balance goes to zero) or there are no splits left. */
137  while (1)
138  {
139  Split *subsplit;
140 
141  subsplit = xaccSplitAssignToLot (split, lot);
142  if (subsplit == split)
143  {
144  PERR ("Accounting Policy gave us a split that "
145  "doesn't fit into this lot\n"
146  "lot baln=%s, isclosed=%d, aplit amt=%s",
148  gnc_lot_is_closed (lot),
149  gnc_num_dbg_to_string (split->amount));
150  break;
151  }
152 
153  if (gnc_lot_is_closed (lot)) break;
154 
155  split = pcy->PolicyGetSplit (pcy, lot);
156  if (!split) break;
157  }
158  xaccAccountCommitEdit (acc);
159  LEAVE ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), xaccAccountGetName(acc));
160 }
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
STRUCTS.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:237
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.c:438
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot...
Definition: cap-gains.c:222
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
Definition: Transaction.c:2650
gboolean gnc_lot_is_closed(GNCLot *lot)
The gnc_lot_is_closed() routine returns a boolean flag: is this lot closed? A lot is closed if its ba...
Definition: gnc-lot.c:377
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.c:1295
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.c:387
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.c:3032
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.c:1336
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
Definition: Account.c:1895
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:488

◆ xaccLotScrubDoubleBalance()

void xaccLotScrubDoubleBalance ( GNCLot *  lot)

The xaccLotScrubDoubleBalance() routine examines the indicated lot.

If it is open, it does nothing. If it is closed, it then verifies that the lot is 'double balanced'. By 'double balance', we mean that both the sum of the split amounts is zero, and that the sum of the split values is zero. If the lot is closed and the sum of the values is not zero, the lot is considered to have a 'realized gain or loss' that hadn't been correctly handled. This routine then creates a balancing transaction to so as to record the realized gain/loss, adds it to the lot, and adds it to a gain/loss account. If there is no default gain/loss account, it creates one.

Definition at line 165 of file Scrub2.c.

166 {
167  gnc_commodity *currency = NULL;
168  SplitList *snode;
169  GList *node;
170  gnc_numeric zero = gnc_numeric_zero();
171  gnc_numeric value = zero;
172 
173  if (!lot) return;
174 
175  ENTER ("lot=%s", gnc_lot_get_title(lot));
176 
177  for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
178  {
179  Split *s = snode->data;
180  xaccSplitComputeCapGains (s, NULL);
181  }
182 
183  /* We double-check only closed lots */
184  if (FALSE == gnc_lot_is_closed (lot))
185  {
186  LEAVE ("lot=%s is closed", gnc_lot_get_title(lot));
187  return;
188  }
189 
190  for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
191  {
192  Split *s = snode->data;
193  Transaction *trans = s->parent;
194 
195  /* Check to make sure all splits in the lot have a common currency */
196  if (NULL == currency)
197  {
198  currency = trans->common_currency;
199  }
200  if (FALSE == gnc_commodity_equiv (currency, trans->common_currency))
201  {
202  /* This lot has mixed currencies. Can't double-balance.
203  * Silently punt */
204  PWARN ("Lot with multiple currencies:\n"
205  "\ttrans=%s curr=%s", xaccTransGetDescription(trans),
206  gnc_commodity_get_fullname(trans->common_currency));
207  break;
208  }
209 
210  /* Now, total up the values */
211  value = gnc_numeric_add (value, xaccSplitGetValue (s),
213  PINFO ("Split=%p value=%s Accum Lot value=%s", s,
214  gnc_num_dbg_to_string (s->value),
215  gnc_num_dbg_to_string (value));
216 
217  }
218 
219  if (FALSE == gnc_numeric_equal (value, zero))
220  {
221  /* Unhandled error condition. Not sure what to do here,
222  * Since the ComputeCapGains should have gotten it right.
223  * I suppose there might be small rounding errors, a penny or two,
224  * the ideal thing would to figure out why there's a rounding
225  * error, and fix that.
226  */
227  PERR ("Closed lot fails to double-balance !! lot value=%s",
228  gnc_num_dbg_to_string (value));
229  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
230  {
231  Split *s = node->data;
232  PERR ("s=%p amt=%s val=%s", s,
233  gnc_num_dbg_to_string(s->amount),
234  gnc_num_dbg_to_string(s->value));
235  }
236  }
237 
238  LEAVE ("lot=%s", gnc_lot_get_title(lot));
239 }
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:249
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split...
Definition: cap-gains.c:528
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:237
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:189
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.c:438
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:243
GList SplitList
GList of Split.
Definition: gnc-engine.h:203
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot.
Definition: gnc-lot.c:418
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Definition: Transaction.c:2280
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Retrieve the full name for the specified commodity.
gboolean gnc_lot_is_closed(GNCLot *lot)
The gnc_lot_is_closed() routine returns a boolean flag: is this lot closed? A lot is closed if its ba...
Definition: gnc-lot.c:377
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Definition: Split.c:1935
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
Definition: gnc-numeric.h:246
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.

◆ xaccScrubLot()

gboolean xaccScrubLot ( GNCLot *  lot)

The xaccScrubLot() routine makes sure that the indicated lot is self-consistent and properly balanced, and fixes it if its not.

This is an important routine to call if the amount of any split in the lot is changed. That's because (obviously) changing split values is guaranteed to throw off lot balances. This routine may end up closing the lot, or at least trying to. It will also cause cap gains to be recomputed.

Scrubbing the lot may cause subsplits to be merged together, i.e. for splits to be deleted. This routine returns true if any splits were deleted.

Definition at line 85 of file Scrub3.c.

86 {
87  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  if (!lot) return FALSE;
94  ENTER ("(lot=%p) %s", lot, gnc_lot_get_title(lot));
95 
96  acc = gnc_lot_get_account (lot);
97  pcy = gnc_account_get_policy(acc);
99  xaccScrubMergeLotSubSplits (lot, TRUE);
100 
101  /* If the lot balance is zero, we don't need to rebalance */
102  lot_baln = gnc_lot_get_balance (lot);
103  PINFO ("lot baln=%s for %s", gnc_num_dbg_to_string (lot_baln),
104  gnc_lot_get_title(lot));
105  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  pcy->PolicyGetLotOpening (pcy, lot, &opening_baln, NULL, NULL);
112  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  opening_baln_is_pos = gnc_numeric_positive_p(opening_baln);
117  lot_baln_is_pos = gnc_numeric_positive_p(lot_baln);
118  if ((opening_baln_is_pos || lot_baln_is_pos) &&
119  ((!opening_baln_is_pos) || (!lot_baln_is_pos)))
120  {
121 rethin:
122  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
123  {
124  Split *s = node->data;
125  if (pcy->PolicyIsOpeningSplit (pcy, lot, s)) continue;
126  gnc_lot_remove_split (lot, s);
127  goto rethin;
128  }
129  }
130 
131  /* At this point the lot is thin, so try to fill it */
132  xaccLotFill (lot);
133 
134  /* Make sure there are no subsplits. */
135  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  if (gains_possible (lot))
146  {
147  xaccLotComputeCapGains (lot, NULL);
149  }
151 
152  LEAVE ("(lot=%s, deleted=%d)", gnc_lot_get_title(lot), splits_deleted);
153  return splits_deleted;
154 }
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
The xaccScrubMergeLotSubSplits() routine does the same as the xaccScrubMergSubSplits, except that it does it for all of the splits in the lot.
Definition: Scrub2.c:384
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
void xaccLotFill(GNCLot *lot)
The xaccLotFill() routine attempts to assign splits to the indicated lot until the lot balance goes t...
Definition: Scrub2.c:97
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:249
STRUCTS.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.c:438
GList SplitList
GList of Split.
Definition: gnc-engine.h:203
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot.
Definition: gnc-lot.c:418
void xaccLotScrubDoubleBalance(GNCLot *lot)
The xaccLotScrubDoubleBalance() routine examines the indicated lot.
Definition: Scrub2.c:165
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.c:1295
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.c:387
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.c:1336
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
Definition: Account.c:1895
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:488

◆ xaccScrubMergeSubSplits()

gboolean xaccScrubMergeSubSplits ( Split *  split,
gboolean  strict 
)

The xaccScrubMergeSubSplits() routine will merge together all of the splits that were at one time split off from this split, but are no longer needed to be kept separate.

Splits might be split up if they need to be divided over multiple lots; they can be merged back together if the lots change. In particular, two sub-splits may be merged if they are in the same lot, or in no lot. Note that, by definition, all subsplits belong to the same transaction.

There are two ways to find matching subsplits. The first way will consider splits to be subsplits only if they are explicitly marked as such while splitting the original split. Set strict to TRUE for this matching algorhythm.

The second way is more relaxed. It will consider any two splits that happen to be part of the same lot and the same transaction to be subsplits. Set strict to FALSE for this matching algorhythm.

The routine returns TRUE if a merger was performed, else it returns FALSE.

Definition at line 323 of file Scrub2.c.

324 {
325  gboolean rc = FALSE;
326  Transaction *txn;
327  SplitList *node;
328  GNCLot *lot;
329 
330  if (strict && (FALSE == is_subsplit (split))) return FALSE;
331 
332  txn = split->parent;
333 
334  // Don't mess with splits from an invoice transaction
335  // Those are the responsibility of the business code
336  if (gncInvoiceGetInvoiceFromTxn (txn)) return FALSE;
337 
338  lot = xaccSplitGetLot (split);
339 
340  ENTER ("(Lot=%s)", gnc_lot_get_title(lot));
341 restart:
342  for (node = txn->splits; node; node = node->next)
343  {
344  Split *s = node->data;
345  if (xaccSplitGetLot (s) != lot) continue;
346  if (s == split) continue;
347  if (qof_instance_get_destroying(s)) continue;
348 
349  // Don't mess with splits from an invoice transaction
350  // Those are the responsibility of the business code
351  if (gncInvoiceGetInvoiceFromTxn (s->parent)) return FALSE;
352 
353  if (strict)
354  {
355  /* OK, this split is in the same lot (and thus same account)
356  * as the indicated split. Make sure it is really a subsplit
357  * of the split we started with. It's possible to have two
358  * splits in the same lot and transaction that are not subsplits
359  * of each other, the test-period test suite does this, for
360  * example. Only worry about adjacent sub-splits. By
361  * repeatedly merging adjacent subsplits, we'll get the non-
362  * adjacent ones too. */
363  if (!xaccSplitIsPeerSplit (split, s))
364  continue;
365  }
366 
367  merge_splits (split, s);
368  rc = TRUE;
369  goto restart;
370  }
371  if (rc && gnc_numeric_zero_p (split->amount))
372  {
373  time64 pdate = xaccTransGetDate (txn);
374  gchar *pdatestr = gnc_ctime (&pdate);
375  PWARN ("Result of merge has zero amt!");
376  PWARN ("Transaction details - posted date %s - description %s", pdatestr, xaccTransGetDescription(txn));
377  g_free (pdatestr);
378  }
379  LEAVE (" splits merged=%d", rc);
380  return rc;
381 }
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2322
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Given a transaction, find and return the Invoice.
Definition: gncInvoice.c:1208
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.c:438
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:243
GList SplitList
GList of Split.
Definition: gnc-engine.h:203
gboolean xaccSplitIsPeerSplit(const Split *split, const Split *other_split)
Report if a split is a peer of this one.
Definition: Split.c:2045
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Definition: Transaction.c:2280
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:83
char * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition: gnc-date.cpp:233
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn't be...
Definition: Split.c:1895

◆ xaccSplitScrub()

void xaccSplitScrub ( Split *  split)

The xaccSplitScrub method ensures that if this split has the same commodity and currency, then it will have the same amount and value.

If the commodity is the currency, the split->amount is set to the split value. In addition, if this split is an orphan, that is fixed first. If the split account doesn't have a commodity declared, an attempt is made to fix that first.

Definition at line 191 of file Scrub.c.

192 {
193  Account *account;
194  Transaction *trans;
195  gnc_numeric value, amount;
196  gnc_commodity *currency, *acc_commodity;
197  int scu;
198 
199  if (!split) return;
200  ENTER ("(split=%p)", split);
201 
202  trans = xaccSplitGetParent (split);
203  if (!trans)
204  {
205  LEAVE("no trans");
206  return;
207  }
208 
209  account = xaccSplitGetAccount (split);
210 
211  /* If there's no account, this split is an orphan.
212  * We need to fix that first, before proceeding.
213  */
214  if (!account)
215  {
216  xaccTransScrubOrphans (trans);
217  account = xaccSplitGetAccount (split);
218  }
219 
220  /* Grrr... the register gnc_split_register_load() line 203 of
221  * src/register/ledger-core/split-register-load.c will create
222  * free-floating bogus transactions. Ignore these for now ...
223  */
224  if (!account)
225  {
226  PINFO ("Free Floating Transaction!");
227  LEAVE ("no account");
228  return;
229  }
230 
231  /* Split amounts and values should be valid numbers */
232  value = xaccSplitGetValue (split);
233  if (gnc_numeric_check (value))
234  {
235  value = gnc_numeric_zero();
236  xaccSplitSetValue (split, value);
237  }
238 
239  amount = xaccSplitGetAmount (split);
240  if (gnc_numeric_check (amount))
241  {
242  amount = gnc_numeric_zero();
243  xaccSplitSetAmount (split, amount);
244  }
245 
246  currency = xaccTransGetCurrency (trans);
247 
248  /* If the account doesn't have a commodity,
249  * we should attempt to fix that first.
250  */
251  acc_commodity = xaccAccountGetCommodity(account);
252  if (!acc_commodity)
253  {
254  xaccAccountScrubCommodity (account);
255  }
256  if (!acc_commodity || !gnc_commodity_equiv(acc_commodity, currency))
257  {
258  LEAVE ("(split=%p) inequiv currency", split);
259  return;
260  }
261 
262  scu = MIN (xaccAccountGetCommoditySCU (account),
263  gnc_commodity_get_fraction (currency));
264 
265  if (gnc_numeric_same (amount, value, scu, GNC_HOW_RND_ROUND_HALF_UP))
266  {
267  LEAVE("(split=%p) different values", split);
268  return;
269  }
270 
271  /*
272  * This will be hit every time you answer yes to the dialog "The
273  * current transaction has changed. Would you like to record it.
274  */
275  PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
276  " old amount %s %s, new amount %s",
277  trans->description, split->memo,
279  gnc_commodity_get_mnemonic (currency),
281 
282  xaccTransBeginEdit (trans);
283  xaccSplitSetAmount (split, value);
284  xaccTransCommitEdit (trans);
285  LEAVE ("(split=%p)", split);
286 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
Definition: Split.c:1258
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:249
void xaccAccountScrubCommodity(Account *account)
The xaccAccountScrubCommodity method fixed accounts without a commodity by using the old account curr...
Definition: Scrub.c:1197
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.c:2456
STRUCTS.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition: Split.c:1845
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
Definition: Split.c:1222
void xaccTransScrubOrphans(Transaction *trans)
The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.
Definition: Scrub.c:139
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Definition: Transaction.c:1642
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
Definition: Transaction.c:1443
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Definition: Split.c:1935
Account * xaccSplitGetAccount(const Split *s)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: Split.c:929
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.c:3155
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1355
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
int gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Equivalence predicate: Convert both a and b to denom using the specified DENOM and method HOW...
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Definition: Split.c:1929

◆ xaccTransScrubCurrency()

void xaccTransScrubCurrency ( Transaction *  trans)

The xaccTransScrubCurrency method fixes transactions without a common_currency by looking for the most commonly used currency among all the splits in the transaction.

If this fails it falls back to using the old account currency and security fields of the parent accounts of the transaction's splits.

Definition at line 1080 of file Scrub.c.

1081 {
1082  SplitList *node;
1083  gnc_commodity *currency;
1084 
1085  if (!trans) return;
1086 
1087  /* If there are any orphaned splits in a transaction, then the
1088  * this routine will fail. Therefore, we want to make sure that
1089  * there are no orphans (splits without parent account).
1090  */
1091  xaccTransScrubOrphans (trans);
1092 
1093  currency = xaccTransGetCurrency (trans);
1094  if (currency && gnc_commodity_is_currency(currency)) return;
1095 
1096  currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans));
1097  if (currency)
1098  {
1099  xaccTransBeginEdit (trans);
1100  xaccTransSetCurrency (trans, currency);
1101  xaccTransCommitEdit (trans);
1102  }
1103  else
1104  {
1105  if (NULL == trans->splits)
1106  {
1107  PWARN ("Transaction \"%s\" has no splits in it!", trans->description);
1108  }
1109  else
1110  {
1111  SplitList *node;
1112  char guid_str[GUID_ENCODING_LENGTH + 1];
1113  guid_to_string_buff(xaccTransGetGUID(trans), guid_str);
1114  PWARN ("no common transaction currency found for trans=\"%s\" (%s);",
1115  trans->description, guid_str);
1116 
1117  for (node = trans->splits; node; node = node->next)
1118  {
1119  Split *split = node->data;
1120  if (NULL == split->acc)
1121  {
1122  PWARN (" split=\"%s\" is not in any account!", split->memo);
1123  }
1124  else
1125  {
1126  gnc_commodity *currency = xaccAccountGetCommodity(split->acc);
1127  PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"",
1128  split->memo, xaccAccountGetName(split->acc),
1129  gnc_commodity_get_mnemonic(currency));
1130 
1131  xaccTransBeginEdit (trans);
1132  xaccTransSetCurrency (trans, currency);
1133  xaccTransCommitEdit (trans);
1134  return;
1135  }
1136  }
1137  }
1138  return;
1139  }
1140 
1141  for (node = trans->splits; node; node = node->next)
1142  {
1143  Split *sp = node->data;
1144 
1146  xaccSplitGetValue (sp)))
1147  {
1148  gnc_commodity *acc_currency;
1149 
1150  acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : NULL;
1151  if (acc_currency == currency)
1152  {
1153  /* This Split needs fixing: The transaction-currency equals
1154  * the account-currency/commodity, but the amount/values are
1155  * inequal i.e. they still correspond to the security
1156  * (amount) and the currency (value). In the new model, the
1157  * value is the amount in the account-commodity -- so it
1158  * needs to be set to equal the amount (since the
1159  * account-currency doesn't exist anymore).
1160  *
1161  * Note: Nevertheless we lose some information here. Namely,
1162  * the information that the 'amount' in 'account-old-security'
1163  * was worth 'value' in 'account-old-currency'. Maybe it would
1164  * be better to store that information in the price database?
1165  * But then, for old currency transactions there is still the
1166  * 'other' transaction, which is going to keep that
1167  * information. So I don't bother with that here. -- cstim,
1168  * 2002/11/20. */
1169 
1170  PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
1171  " old amount %s %s, new amount %s",
1172  trans->description, sp->memo,
1174  gnc_commodity_get_mnemonic (currency),
1176  xaccTransBeginEdit (trans);
1178  xaccTransCommitEdit (trans);
1179  }
1180  /*else
1181  {
1182  PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
1183  xaccSplitGetMemo (sp),
1184  gnc_num_dbg_to_string (amount),
1185  gnc_commodity_get_mnemonic (currency),
1186  gnc_num_dbg_to_string (value),
1187  gnc_commodity_get_mnemonic (acc_currency));
1188  }*/
1189  }
1190  }
1191 
1192 }
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency or a legacy currency...
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:174
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1414
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:243
GList SplitList
GList of Split.
Definition: gnc-engine.h:203
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
Definition: Split.c:1222
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
void xaccTransScrubOrphans(Transaction *trans)
The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.
Definition: Scrub.c:139
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Definition: Transaction.c:1642
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
Definition: Transaction.c:1443
#define xaccTransGetGUID(X)
Definition: Transaction.h:770
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Definition: Split.c:1935
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.c:3155
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1355
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.c:3032
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Definition: Split.c:1929

◆ xaccTransScrubImbalance()

void xaccTransScrubImbalance ( Transaction *  trans,
Account root,
Account account 
)

The xaccScrubImbalance() method searches for transactions that do not balance to zero.

If any such transactions are found, a split is created to offset this amount and is added to an "imbalance" account.

The xaccScrubImbalance() method searches for transactions that do not balance to zero.

Parameters
transThe Transaction
rootThe (hidden) root account, for the book default currency.
accountThe account whose currency in which to balance.

Definition at line 803 of file Scrub.c.

805 {
806  gnc_numeric imbalance;
807 
808  if (!trans) return;
809 
810  ENTER ("()");
811 
812  /* Must look for orphan splits even if there is no imbalance. */
813  xaccTransScrubSplits (trans);
814 
815  /* Return immediately if things are balanced. */
816  if (xaccTransIsBalanced (trans))
817  {
818  LEAVE ("transaction is balanced");
819  return;
820  }
821 
822  if (! xaccTransUseTradingAccounts (trans))
823  {
824  gnc_transaction_balance_no_trading (trans, root, account);
825  LEAVE ("transaction balanced, no trading accounts");
826  return;
827  }
828 
829  imbalance = gnc_transaction_adjust_trading_splits (trans, root);
830 
831  /* Balance the value, ignoring existing trading splits */
832  if (! gnc_numeric_zero_p (imbalance))
833  {
834  PINFO ("Value unbalanced transaction");
835 
836  add_balance_split (trans, imbalance, root, account);
837  }
838 
839  gnc_transaction_balance_trading (trans, root);
841  {
842  LEAVE ("()");
843  return;
844  }
845  /* If the transaction is still not balanced, it's probably because there
846  are splits with zero amount and non-zero value. These are usually
847  realized gain/loss splits. Add a reversing split for each of them to
848  balance the value. */
849 
850  gnc_transaction_balance_trading_more_splits (trans, root);
852  PERR("Balancing currencies unbalanced value");
853 
854 }
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
Definition: Transaction.c:1022
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:249
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
gboolean xaccTransIsBalanced(const Transaction *trans)
Returns true if the transaction is balanced according to the rules currently in effect.
Definition: Transaction.c:1131
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:237
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:261
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
The xaccTransGetImbalanceValue() method returns the total value of the transaction.
Definition: Transaction.c:1043
void xaccTransScrubSplits(Transaction *trans)
The xacc*ScrubSplits() calls xaccSplitScrub() on each split in the respective structure: transaction...
Definition: Transaction.c:2761
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271

◆ xaccTransScrubPostedDate()

void xaccTransScrubPostedDate ( Transaction *  trans)

Changes Transaction date_posted timestamps from 00:00 local to 11:00 UTC.

11:00 UTC is the same day local time in almost all timezones, the exceptions being the -12, +13, and +14 timezones along the International Date Line. If Local time is set to one of these timezones then the new date_posted time will be adjusted as needed to ensure that the date doesn't change there. This change was made for v2.6.14 to partially resolve bug 137017.

Definition at line 1405 of file Scrub.c.

1406 {
1407  time64 orig = xaccTransGetDate(trans);
1408  GDate date = xaccTransGetDatePostedGDate(trans);
1409  Timespec ts = gdate_to_timespec(date);
1410  if (orig && orig != ts.tv_sec)
1411  {
1412  /* xaccTransSetDatePostedTS handles committing the change. */
1413  xaccTransSetDatePostedTS(trans, &ts);
1414  }
1415 }
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2322
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:83
Timespec gdate_to_timespec(GDate d)
Turns a GDate into a Timespec, returning the first second of the day.
Definition: gnc-date.cpp:1348
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2357
void xaccTransSetDatePostedTS(Transaction *trans, const Timespec *ts)
The xaccTransSetDatePostedTS() method does the same thing as xaccTransSetDatePostedSecs(), but takes a struct timespec64.
Definition: Transaction.c:2020