GnuCash  5.6-133-gc519490283+
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 gnc_set_abort_scrub (gboolean abort)
 The gnc_set_abort_scrub () method causes a currently running scrub operation to stop, if abort is TRUE; gnc_set_abort_scrub(FALSE) must be called before any scrubbing operation.
 
gboolean gnc_get_abort_scrub (void)
 
gboolean gnc_get_ongoing_scrub (void)
 The gnc_get_ongoing_scrub () method returns TRUE if a scrub operation is ongoing.
 
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 xaccAccountScrubColorNotSet (QofBook *book)
 Remove color slots that have a "Not Set" value, since 2.4.0, fixed in 3.4 This should only be run once on a book.
 
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 736 of file ScrubBusiness.c.

737 {
738  if (!acc) return;
739  if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
740 
741  gncScrubBusinessAccountLots (acc, percentagefunc);
742  gncScrubBusinessAccountSplits (acc, percentagefunc);
743 }
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition: Account.cpp:3282
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.cpp:4674

◆ 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 620 of file ScrubBusiness.c.

621 {
622  LotList *lots, *node;
623  gint lot_count = 0;
624  gint curr_lot_no = 0;
625  const gchar *str;
626  const char *message = _( "Checking business lots in account %s: %u of %u");
627 
628  if (!acc) return;
629 
630  if (gnc_get_abort_scrub())
631  (percentagefunc)(NULL, -1.0);
632 
633  if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
634 
635  str = xaccAccountGetName(acc);
636  str = str ? str : "(null)";
637 
638  ENTER ("(acc=%s)", str);
639  PINFO ("Cleaning up superfluous lot links in account %s\n", str);
641 
642  lots = xaccAccountGetLotList(acc);
643  lot_count = g_list_length (lots);
644  for (node = lots; node; node = node->next)
645  {
646  GNCLot *lot = node->data;
647 
648  PINFO("Start processing lot %d of %d",
649  curr_lot_no + 1, lot_count);
650 
651  if (curr_lot_no % 100 == 0)
652  {
653  char *progress_msg = g_strdup_printf (message, str, curr_lot_no, lot_count);
654  (percentagefunc)(progress_msg, (100 * curr_lot_no) / lot_count);
655  g_free (progress_msg);
656  }
657 
658  if (lot)
659  gncScrubBusinessLot (lot);
660 
661  PINFO("Finished processing lot %d of %d",
662  curr_lot_no + 1, lot_count);
663  curr_lot_no++;
664  }
665  g_list_free(lots);
667  (percentagefunc)(NULL, -1.0);
668  LEAVE ("(acc=%s)", str);
669 }
GList LotList
GList of GNCLots.
Definition: gnc-engine.h:205
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition: Account.cpp:3282
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition: Account.cpp:4049
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4674
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.cpp:1485
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.cpp:3304
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1526

◆ 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 467 of file ScrubBusiness.c.

468 {
469  gboolean splits_deleted = FALSE;
470  gboolean dangling_payments = FALSE;
471  gboolean dangling_lot_link = FALSE;
472  Account *acc;
473  gchar *lotname=NULL;
474 
475  if (!lot) return FALSE;
476  lotname = g_strdup (gnc_lot_get_title (lot));
477  ENTER ("(lot=%p) %s", lot, lotname ? lotname : "(no lotname)");
478 
479  acc = gnc_lot_get_account (lot);
480  if (acc)
482 
483  /* Check invoice link consistency
484  * A lot should have both or neither of:
485  * - one split from an invoice transaction
486  * - an invoice-guid set
487  */
488  gncScrubInvoiceState (lot);
489 
490  // Scrub lot links.
491  // They should only remain when two document lots are linked together
492  xaccScrubMergeLotSubSplits (lot, FALSE);
493  splits_deleted = gncScrubLotLinks (lot);
494 
495  // Look for dangling payments and repair if found
496  dangling_lot_link = gncScrubLotIsSingleLotLinkSplit (lot);
497  if (dangling_lot_link)
498  {
499  dangling_payments = gncScrubLotDanglingPayments (lot);
500  if (dangling_payments)
501  splits_deleted |= gncScrubLotLinks (lot);
502  else
503  {
504  Split *split = gnc_lot_get_earliest_split (lot);
505  Transaction *trans = xaccSplitGetParent (split);
506  xaccTransDestroy (trans);
507  }
508  }
509 
510  // If lot is empty now, delete it
511  if (0 == gnc_lot_count_splits (lot))
512  {
513  PINFO("All splits were removed from lot, deleting");
514  gnc_lot_destroy (lot);
515  }
516 
517  if (acc)
519 
520  LEAVE ("(lot=%s, deleted=%d, dangling lot link=%d, dangling_payments=%d)",
521  lotname ? lotname : "(no lotname)", splits_deleted, dangling_lot_link,
522  dangling_payments);
523  g_free (lotname);
524 
525  return splits_deleted;
526 }
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.cpp:379
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
STRUCTS.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
Split * gnc_lot_get_earliest_split(GNCLot *lot)
The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the earliest da...
Definition: gnc-lot.cpp:673
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.cpp:445
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1485
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
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.cpp:377
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1526

◆ 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://bugs.gnucash.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 529 of file ScrubBusiness.c.

530 {
531  Transaction *txn;
532  gboolean deleted_split = FALSE;
533 
534  if (!split) return FALSE;
535  ENTER ("(split=%p)", split);
536 
537  txn = xaccSplitGetParent (split);
538  if (txn)
539  {
540  gchar txntype = xaccTransGetTxnType (txn);
541  const gchar *read_only = xaccTransGetReadOnly (txn);
542  gboolean is_void = xaccTransGetVoidStatus (txn);
543  GNCLot *lot = xaccSplitGetLot (split);
544  GncInvoice *invoice = gncInvoiceGetInvoiceFromTxn (txn);
545  Transaction *posted_txn = gncInvoiceGetPostedTxn (invoice);
546 
547  /* Look for transactions as a result of double posting an invoice or bill
548  * Refer to https://bugs.gnucash.org/show_bug.cgi?id=754209
549  * to learn how this could have happened in the past.
550  * Characteristics of such transaction are:
551  * - read only
552  * - not voided (to ensure read only is set by the business functions)
553  * - transaction type is none (should be type invoice for proper post transactions)
554  * - assigned to a lot
555  */
556  if ((txntype == TXN_TYPE_NONE) && read_only && !is_void && lot)
557  {
558  const gchar *memo = _("Please delete this transaction. Explanation at https://wiki.gnucash.org/wiki/Business_Features_Issues#Double_posting");
559  gchar *txn_date = qof_print_date (xaccTransGetDateEntered (txn));
560  xaccTransClearReadOnly (txn);
561  xaccSplitSetMemo (split, memo);
562  gnc_lot_remove_split (lot, split);
563  PWARN("Cleared double post status of transaction \"%s\", dated %s. "
564  "Please delete transaction and verify balance.",
566  txn_date);
567  g_free (txn_date);
568  }
569  /* Next check for transactions which claim to be the posted transaction of
570  * an invoice but the invoice disagrees. In that case
571  */
572  else if (invoice && (txn != posted_txn))
573  {
574  const gchar *memo = _("Please delete this transaction. Explanation at https://wiki.gnucash.org/wiki/Business_Features_Issues#I_can.27t_delete_a_transaction_of_type_.22I.22_from_the_AR.2FAP_account");
575  gchar *txn_date = qof_print_date (xaccTransGetDateEntered (txn));
576  xaccTransClearReadOnly (txn);
578  xaccSplitSetMemo (split, memo);
579  if (lot)
580  {
581  gnc_lot_remove_split (lot, split);
582  gncInvoiceDetachFromLot (lot);
583  gncOwnerAttachToLot (gncInvoiceGetOwner(invoice), lot);
584  }
585  PWARN("Cleared double post status of transaction \"%s\", dated %s. "
586  "Please delete transaction and verify balance.",
588  txn_date);
589  g_free (txn_date);
590  }
591  /* Next delete any empty splits that aren't part of an invoice transaction
592  * Such splits may be the result of scrubbing the business lots, which can
593  * merge splits together while reducing superfluous lot links
594  */
595  else if (gnc_numeric_zero_p (xaccSplitGetAmount(split)) && !gncInvoiceGetInvoiceFromTxn (txn) && !is_void)
596  {
597  GNCLot *lot = xaccSplitGetLot (split);
598  time64 pdate = xaccTransGetDate (txn);
599  gchar *pdatestr = gnc_ctime (&pdate);
600  PINFO ("Destroying empty split %p from transaction %s (%s)", split, pdatestr, xaccTransGetDescription(txn));
601  xaccSplitDestroy (split);
602  g_free (pdatestr);
603 
604  // Also delete the lot containing this split if it was the last split in that lot
605  if (lot && (gnc_lot_count_splits (lot) == 0))
606  gnc_lot_destroy (lot);
607 
608  deleted_split = TRUE;
609  }
610 
611  }
612 
613  LEAVE ("(split=%p)", split);
614  return deleted_split;
615 }
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
char xaccTransGetTxnType(Transaction *trans)
Returns the Transaction Type: note this type will be derived from the transaction splits...
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1504
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
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.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Given a transaction, find and return the Invoice.
Definition: gncInvoice.c:1327
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
void xaccTransSetTxnType(Transaction *trans, char type)
Set the Transaction Type: note the type will be saved into the Transaction kvp property as a backward...
#define TXN_TYPE_NONE
No transaction type.
Definition: Transaction.h:125
char * qof_print_date(time64 secs)
Convenience; calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:608
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
void gncOwnerAttachToLot(const GncOwner *owner, GNCLot *lot)
Attach an owner to a lot.
Definition: gncOwner.c:622
time64 xaccTransGetDateEntered(const Transaction *trans)
Retrieve the date of when the transaction was entered.
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
char * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition: gnc-date.cpp:255
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.cpp:1915
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Definition: gmock-Split.cpp:69

◆ 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.cpp.

60 {
61  if (!acc) return;
62 
63  ENTER ("acc=%s", xaccAccountGetName(acc));
65 
66 restart_loop:
67  for (auto split : xaccAccountGetSplits (acc))
68  {
69  /* If already in lot, then no-op */
70  if (split->lot) continue;
71 
72  /* Skip voided transactions */
73  if (gnc_numeric_zero_p (split->amount) &&
74  xaccTransGetVoidStatus(split->parent)) continue;
75 
76  if (xaccSplitAssign (split)) goto restart_loop;
77  }
79  LEAVE ("acc=%s", xaccAccountGetName(acc));
80 }
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:272
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
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.cpp:426
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1485
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.cpp:3304
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1526

◆ xaccAccountScrubCommodity()

void xaccAccountScrubCommodity ( Account account)

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

Definition at line 1228 of file Scrub.cpp.

1229 {
1230  gnc_commodity *commodity;
1231 
1232  if (!account) return;
1233  if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return;
1234 
1235  commodity = xaccAccountGetCommodity (account);
1236  if (commodity) return;
1237 
1238  /* Use the 'obsolete' routines to try to figure out what the
1239  * account commodity should have been. */
1240  commodity = xaccAccountGetCommodity (account);
1241  if (commodity)
1242  {
1243  xaccAccountSetCommodity (account, commodity);
1244  return;
1245  }
1246 
1247  commodity = DxaccAccountGetCurrency (account);
1248  if (commodity)
1249  {
1250  xaccAccountSetCommodity (account, commodity);
1251  return;
1252  }
1253 
1254  PERR ("Account \"%s\" does not have a commodity!",
1255  xaccAccountGetName(account));
1256 }
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition: Account.cpp:3445
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition: Account.cpp:3282
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.cpp:3467
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.cpp:3304
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.cpp:2637

◆ xaccAccountScrubKvp()

void xaccAccountScrubKvp ( Account account)

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

Definition at line 1374 of file Scrub.cpp.

1375 {
1376  GValue v = G_VALUE_INIT;
1377  gchar *str2;
1378 
1379  if (!account) return;
1380  scrub_depth++;
1381 
1382  qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "notes");
1383  if (G_VALUE_HOLDS_STRING (&v))
1384  {
1385  str2 = g_strstrip(g_value_dup_string(&v));
1386  if (strlen(str2) == 0)
1387  qof_instance_slot_delete (QOF_INSTANCE (account), "notes");
1388  g_free(str2);
1389  }
1390 
1391  qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "placeholder");
1392  if ((G_VALUE_HOLDS_STRING (&v) &&
1393  strcmp(g_value_get_string (&v), "false") == 0) ||
1394  (G_VALUE_HOLDS_BOOLEAN (&v) && ! g_value_get_boolean (&v)))
1395  qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
1396 
1397  g_value_unset (&v);
1398  qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
1399  scrub_depth--;
1400 }
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
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.cpp.

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 = GNC_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:205
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.cpp:80
void xaccAccountAssignLots(Account *acc)
Loop over all splits, and make sure that every split belongs to some lot.
Definition: Scrub2.cpp:59
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition: Account.cpp:4049
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1485
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gboolean xaccScrubLot(GNCLot *lot)
The xaccScrubLot() routine makes sure that the indicated lot is self-consistent and properly balanced...
Definition: Scrub3.cpp:85
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.cpp:3304
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1526

◆ 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 1293 of file Scrub.cpp.

1294 {
1295  if (!acc) return;
1296  scrub_depth++;
1297  xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, nullptr);
1298 
1299  scrub_account_commodity_helper (acc, nullptr);
1300  gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, nullptr);
1301  scrub_depth--;
1302 }
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.cpp:3248

◆ 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 1351 of file Scrub.cpp.

1352 {
1353  gboolean new_style = FALSE;
1354  ENTER(" ");
1355 
1356  if (!root || !table)
1357  {
1358  LEAVE("Oops");
1359  return;
1360  }
1361  scrub_depth++;
1362  gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
1363 
1364  move_quote_source(root, GINT_TO_POINTER(new_style));
1365  gnc_account_foreach_descendant (root, move_quote_source,
1366  GINT_TO_POINTER(new_style));
1367  LEAVE("Migration done");
1368  scrub_depth--;
1369 }
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.cpp:3248
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282

◆ 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 92 of file Scrub2.cpp.

93 {
94  Account *acc;
95  Split *split;
96  GNCPolicy *pcy;
97 
98  if (!lot) return;
99  acc = gnc_lot_get_account(lot);
100  pcy = gnc_account_get_policy(acc);
101 
102  ENTER ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), xaccAccountGetName(acc));
103 
104  /* If balance already zero, we have nothing to do. */
105  if (gnc_lot_is_closed (lot))
106  {
107  LEAVE ("Lot Closed (lot=%s, acc=%s)", gnc_lot_get_title(lot),
108  xaccAccountGetName(acc));
109  return;
110  }
111  split = pcy->PolicyGetSplit (pcy, lot);
112  if (!split)
113  {
114  LEAVE ("No Split (lot=%s, acc=%s)", gnc_lot_get_title(lot),
115  xaccAccountGetName(acc));
116  return; /* Handle the common case */
117  }
118 
119  /* Reject voided transactions */
120  if (gnc_numeric_zero_p(split->amount) &&
121  xaccTransGetVoidStatus(split->parent))
122  {
123  LEAVE ("Voided transaction (lot=%s, acc=%s)",
125  return;
126  }
127 
128  xaccAccountBeginEdit (acc);
129 
130  /* Loop until we've filled up the lot, (i.e. till the
131  * balance goes to zero) or there are no splits left. */
132  while (1)
133  {
134  Split *subsplit;
135 
136  subsplit = xaccSplitAssignToLot (split, lot);
137  if (subsplit == split)
138  {
139  PERR ("Accounting Policy gave us a split that "
140  "doesn't fit into this lot\n"
141  "lot baln=%s, isclosed=%d, aplit amt=%s",
143  gnc_lot_is_closed (lot),
144  gnc_num_dbg_to_string (split->amount));
145  break;
146  }
147 
148  if (gnc_lot_is_closed (lot)) break;
149 
150  split = pcy->PolicyGetSplit (pcy, lot);
151  if (!split) break;
152  }
153  xaccAccountCommitEdit (acc);
154  LEAVE ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), xaccAccountGetName(acc));
155 }
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:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
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.cpp:445
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot...
Definition: cap-gains.cpp:219
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
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.cpp:367
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1485
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
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.cpp:377
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.cpp:3304
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1526
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
Definition: Account.cpp:2117
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.cpp:502

◆ 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 160 of file Scrub2.cpp.

161 {
162  gnc_commodity *currency = nullptr;
163  SplitList *snode;
164  GList *node;
165  gnc_numeric zero = gnc_numeric_zero();
166  gnc_numeric value = zero;
167 
168  if (!lot) return;
169 
170  ENTER ("lot=%s", gnc_lot_get_title(lot));
171 
172  for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
173  {
174  Split *s = GNC_SPLIT(snode->data);
175  xaccSplitComputeCapGains (s, nullptr);
176  }
177 
178  /* We double-check only closed lots */
179  if (FALSE == gnc_lot_is_closed (lot))
180  {
181  LEAVE ("lot=%s is closed", gnc_lot_get_title(lot));
182  return;
183  }
184 
185  for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
186  {
187  Split *s = GNC_SPLIT(snode->data);
188  Transaction *trans = s->parent;
189 
190  /* Check to make sure all splits in the lot have a common currency */
191  if (nullptr == currency)
192  {
193  currency = trans->common_currency;
194  }
195  if (FALSE == gnc_commodity_equiv (currency, trans->common_currency))
196  {
197  /* This lot has mixed currencies. Can't double-balance.
198  * Silently punt */
199  PWARN ("Lot with multiple currencies:\n"
200  "\ttrans=%s curr=%s", xaccTransGetDescription(trans),
201  gnc_commodity_get_fullname(trans->common_currency));
202  break;
203  }
204 
205  /* Now, total up the values */
206  value = gnc_numeric_add (value, xaccSplitGetValue (s),
208  PINFO ("Split=%p value=%s Accum Lot value=%s", s,
209  gnc_num_dbg_to_string (s->value),
210  gnc_num_dbg_to_string (value));
211 
212  }
213 
214  if (FALSE == gnc_numeric_equal (value, zero))
215  {
216  /* Unhandled error condition. Not sure what to do here,
217  * Since the ComputeCapGains should have gotten it right.
218  * I suppose there might be small rounding errors, a penny or two,
219  * the ideal thing would to figure out why there's a rounding
220  * error, and fix that.
221  */
222  PERR ("Closed lot fails to double-balance !! lot value=%s",
223  gnc_num_dbg_to_string (value));
224  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
225  {
226  Split *s = GNC_SPLIT(node->data);
227  PERR ("s=%p amt=%s val=%s", s,
228  gnc_num_dbg_to_string(s->amount),
229  gnc_num_dbg_to_string(s->value));
230  }
231  }
232 
233  LEAVE ("lot=%s", gnc_lot_get_title(lot));
234 }
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:256
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split...
Definition: cap-gains.cpp:526
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:190
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
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.cpp:445
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
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.cpp:425
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
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.cpp:367
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Definition: gmock-Split.cpp:84
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
Definition: gnc-numeric.h:247
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.cpp.

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, nullptr, nullptr);
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 = GNC_SPLIT(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, nullptr);
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.cpp:379
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.cpp:92
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
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:272
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.cpp:445
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
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.cpp:425
void xaccLotScrubDoubleBalance(GNCLot *lot)
The xaccLotScrubDoubleBalance() routine examines the indicated lot.
Definition: Scrub2.cpp:160
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.cpp:1485
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
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.cpp:377
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1526
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
Definition: Account.cpp:2117
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.cpp:502

◆ 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 algorithm.

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 algorithm.

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

Definition at line 318 of file Scrub2.cpp.

319 {
320  gboolean rc = FALSE;
321  Transaction *txn;
322  SplitList *node;
323  GNCLot *lot;
324 
325  if (strict && (FALSE == is_subsplit (split))) return FALSE;
326 
327  txn = split->parent;
328 
329  // Don't mess with splits from an invoice transaction
330  // Those are the responsibility of the business code
331  if (gncInvoiceGetInvoiceFromTxn (txn)) return FALSE;
332 
333  lot = xaccSplitGetLot (split);
334 
335  ENTER ("(Lot=%s)", gnc_lot_get_title(lot));
336 restart:
337  for (node = txn->splits; node; node = node->next)
338  {
339  Split *s = GNC_SPLIT(node->data);
340  if (xaccSplitGetLot (s) != lot) continue;
341  if (s == split) continue;
342  if (qof_instance_get_destroying(s)) continue;
343 
344  // Don't mess with splits from an invoice transaction
345  // Those are the responsibility of the business code
346  if (gncInvoiceGetInvoiceFromTxn (s->parent)) return FALSE;
347 
348  if (strict)
349  {
350  /* OK, this split is in the same lot (and thus same account)
351  * as the indicated split. Make sure it is really a subsplit
352  * of the split we started with. It's possible to have two
353  * splits in the same lot and transaction that are not subsplits
354  * of each other, the test-period test suite does this, for
355  * example. Only worry about adjacent sub-splits. By
356  * repeatedly merging adjacent subsplits, we'll get the non-
357  * adjacent ones too. */
358  if (!xaccSplitIsPeerSplit (split, s))
359  continue;
360  }
361 
362  merge_splits (split, s);
363  rc = TRUE;
364  goto restart;
365  }
366  if (rc && gnc_numeric_zero_p (split->amount))
367  {
368  time64 pdate = xaccTransGetDate (txn);
369  gchar *pdatestr = gnc_ctime (&pdate);
370  PWARN ("Result of merge has zero amt!");
371  PWARN ("Transaction details - posted date %s - description %s", pdatestr, xaccTransGetDescription(txn));
372  g_free (pdatestr);
373  }
374  LEAVE (" splits merged=%d", rc);
375  return rc;
376 }
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
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:272
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Given a transaction, find and return the Invoice.
Definition: gncInvoice.c:1327
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.cpp:445
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
gboolean xaccSplitIsPeerSplit(const Split *split, const Split *other_split)
Report if a split is a peer of this one.
Definition: Split.cpp:2071
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
char * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition: gnc-date.cpp:255
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.cpp:1915

◆ 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 430 of file Scrub.cpp.

431 {
432  split_scrub_or_dry_run (split, false);
433 }

◆ 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 1111 of file Scrub.cpp.

1112 {
1113  SplitList *node;
1114  gnc_commodity *currency;
1115 
1116  if (!trans) return;
1117 
1118  /* If there are any orphaned splits in a transaction, then the
1119  * this routine will fail. Therefore, we want to make sure that
1120  * there are no orphans (splits without parent account).
1121  */
1122  xaccTransScrubOrphans (trans);
1123 
1124  currency = xaccTransGetCurrency (trans);
1125  if (currency && gnc_commodity_is_currency(currency)) return;
1126 
1127  currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans));
1128  if (currency)
1129  {
1130  xaccTransBeginEdit (trans);
1131  xaccTransSetCurrency (trans, currency);
1132  xaccTransCommitEdit (trans);
1133  }
1134  else
1135  {
1136  if (nullptr == trans->splits)
1137  {
1138  PWARN ("Transaction \"%s\" has no splits in it!", trans->description);
1139  }
1140  else
1141  {
1142  SplitList *node;
1143  char guid_str[GUID_ENCODING_LENGTH + 1];
1144  guid_to_string_buff(xaccTransGetGUID(trans), guid_str);
1145  PWARN ("no common transaction currency found for trans=\"%s\" (%s);",
1146  trans->description, guid_str);
1147 
1148  for (node = trans->splits; node; node = node->next)
1149  {
1150  Split *split = GNC_SPLIT(node->data);
1151  if (nullptr == split->acc)
1152  {
1153  PWARN (" split=\"%s\" is not in any account!", split->memo);
1154  }
1155  else
1156  {
1157  gnc_commodity *currency = xaccAccountGetCommodity(split->acc);
1158  PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"",
1159  split->memo, xaccAccountGetName(split->acc),
1160  gnc_commodity_get_mnemonic(currency));
1161 
1162  xaccTransBeginEdit (trans);
1163  xaccTransSetCurrency (trans, currency);
1164  xaccTransCommitEdit (trans);
1165  return;
1166  }
1167  }
1168  }
1169  return;
1170  }
1171 
1172  for (node = trans->splits; node; node = node->next)
1173  {
1174  Split *sp = GNC_SPLIT(node->data);
1175 
1177  xaccSplitGetValue (sp)))
1178  {
1179  gnc_commodity *acc_currency;
1180 
1181  acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : nullptr;
1182  if (acc_currency == currency)
1183  {
1184  /* This Split needs fixing: The transaction-currency equals
1185  * the account-currency/commodity, but the amount/values are
1186  * inequal i.e. they still correspond to the security
1187  * (amount) and the currency (value). In the new model, the
1188  * value is the amount in the account-commodity -- so it
1189  * needs to be set to equal the amount (since the
1190  * account-currency doesn't exist anymore).
1191  *
1192  * Note: Nevertheless we lose some information here. Namely,
1193  * the information that the 'amount' in 'account-old-security'
1194  * was worth 'value' in 'account-old-currency'. Maybe it would
1195  * be better to store that information in the price database?
1196  * But then, for old currency transactions there is still the
1197  * 'other' transaction, which is going to keep that
1198  * information. So I don't bother with that here. -- cstim,
1199  * 2002/11/20. */
1200 
1201  PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
1202  " old amount %s %s, new amount %s",
1203  trans->description, sp->memo,
1205  gnc_commodity_get_mnemonic (currency),
1207  xaccTransBeginEdit (trans);
1209  xaccTransCommitEdit (trans);
1210  }
1211  /*else
1212  {
1213  PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
1214  xaccSplitGetMemo (sp),
1215  gnc_num_dbg_to_string (amount),
1216  gnc_commodity_get_mnemonic (currency),
1217  gnc_num_dbg_to_string (value),
1218  gnc_commodity_get_mnemonic (acc_currency));
1219  }*/
1220  }
1221  }
1222 
1223 }
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:173
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
Definition: gmock-Split.cpp:77
#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.cpp:184
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
#define xaccTransGetGUID(X)
Definition: Transaction.h:804
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Definition: gmock-Split.cpp:84
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.cpp:3467
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.cpp:3304
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Definition: gmock-Split.cpp:69

◆ 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 835 of file Scrub.cpp.

837 {
838  gnc_numeric imbalance;
839 
840  if (!trans) return;
841 
842  ENTER ("()");
843 
844  /* Must look for orphan splits even if there is no imbalance. */
845  xaccTransScrubSplits (trans);
846 
847  /* Return immediately if things are balanced. */
848  if (xaccTransIsBalanced (trans))
849  {
850  LEAVE ("transaction is balanced");
851  return;
852  }
853 
854  if (! xaccTransUseTradingAccounts (trans))
855  {
856  gnc_transaction_balance_no_trading (trans, root, account);
857  LEAVE ("transaction balanced, no managed trading accounts");
858  return;
859  }
860 
861  xaccTransClearTradingSplits (trans);
862  imbalance = xaccTransGetImbalanceValue (trans);
863  if (! gnc_numeric_zero_p (imbalance))
864  {
865  PINFO ("Value unbalanced transaction");
866 
867  add_balance_split (trans, imbalance, root, account);
868  }
869 
870  gnc_transaction_balance_trading (trans, root);
872  {
873  LEAVE ("()");
874  return;
875  }
876  /* If the transaction is still not balanced, it's probably because there
877  are splits with zero amount and non-zero value. These are usually
878  realized gain/loss splits. Add a reversing split for each of them to
879  balance the value. */
880 
881  gnc_transaction_balance_trading_more_splits (trans, root);
883  PERR("Balancing currencies unbalanced value");
884 
885 }
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
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.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
The xaccTransGetImbalanceValue() method returns the total value of the transaction.
void xaccTransScrubSplits(Transaction *trans)
The xacc*ScrubSplits() calls xaccSplitScrub() on each split in the respective structure: transaction...
Definition: Scrub.cpp:401
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282

◆ 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 1533 of file Scrub.cpp.

1534 {
1535  time64 orig = xaccTransGetDate(trans);
1536  if(orig == INT64_MAX)
1537  {
1538  GDate date = xaccTransGetDatePostedGDate(trans);
1539  time64 time = gdate_to_time64(date);
1540  if(time != INT64_MAX)
1541  {
1542  // xaccTransSetDatePostedSecs handles committing the change.
1543  xaccTransSetDatePostedSecs(trans, time);
1544  }
1545  }
1546 }
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1252
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction, specified by a time64 (see ctime(3)).
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Retrieve the posted date of the transaction.