GnuCash  2.6.16
Files

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)
 
void xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
 
void xaccAccountTreeScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
 
void xaccSplitScrub (Split *split)
 
void xaccTransScrubSplits (Transaction *trans)
 
void xaccAccountScrubSplits (Account *account)
 
void xaccAccountTreeScrubSplits (Account *account)
 
void xaccTransScrubImbalance (Transaction *trans, Account *root, Account *parent)
 
void xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
 
void xaccAccountTreeScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
 
void xaccTransScrubCurrency (Transaction *trans)
 
void xaccAccountScrubCommodity (Account *account)
 
void xaccAccountTreeScrubCommodities (Account *acc)
 
void xaccAccountTreeScrubQuoteSources (Account *root, gnc_commodity_table *table)
 
void xaccAccountScrubKvp (Account *account)
 
void xaccTransScrubPostedDate (Transaction *trans)
 

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)
 
void xaccLotFill (GNCLot *lot)
 
void xaccLotScrubDoubleBalance (GNCLot *lot)
 
gboolean xaccScrubMergeSubSplits (Split *split, gboolean strict)
 
gboolean xaccScrubMergeLotSubSplits (GNCLot *lot, gboolean strict)
 

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)
 
void xaccAccountScrubLots (Account *acc)
 
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)
 
gboolean gncScrubBusinessSplit (Split *split)
 
void gncScrubBusinessAccountLots (Account *acc, QofPercentageFunc percentagefunc)
 
void gncScrubBusinessAccountSplits (Account *acc, QofPercentageFunc percentagefunc)
 
void gncScrubBusinessAccount (Account *acc, QofPercentageFunc percentagefunc)
 
void gncScrubBusinessAccountTree (Account *acc, QofPercentageFunc percentagefunc)
 

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)
Definition: Account.c:2884
void gncScrubBusinessAccountSplits(Account *acc, QofPercentageFunc percentagefunc)
void gncScrubBusinessAccountLots(Account *acc, QofPercentageFunc percentagefunc)
gboolean xaccAccountIsAPARType(GNCAccountType t)
Definition: Account.c:4111

◆ 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
Definition: gnc-engine.h:201
#define PINFO(format, args...)
Definition: qoflog.h:244
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:2884
#define ENTER(format, args...)
Definition: qoflog.h:256
LotList * xaccAccountGetLotList(const Account *acc)
Definition: Account.c:3630
gboolean xaccAccountIsAPARType(GNCAccountType t)
Definition: Account.c:4111
gboolean gncScrubBusinessLot(GNCLot *lot)
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1143
#define LEAVE(format, args...)
Definition: qoflog.h:266
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:2906
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1184

◆ gncScrubBusinessAccountSplits()

void gncScrubBusinessAccountSplits ( Account acc,
QofPercentageFunc  percentagefunc 
)

The gncScrubBusinessAccountSplits() function will call gncScrubBusinessSplit() on each split in the given account.

Definition at line 636 of file ScrubBusiness.c.

637 {
638  SplitList *splits, *node;
639  gint split_count = 0;
640  gint curr_split_no;
641  const gchar *str;
642  const char *message = _( "Checking business splits in account %s: %u of %u");
643 
644  if (!acc) return;
645  if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
646 
647  str = xaccAccountGetName(acc);
648  str = str ? str : "(null)";
649 
650  ENTER ("(acc=%s)", str);
651  PINFO ("Cleaning up superfluous lot links in account %s \n", str);
653 
654 restart:
655  curr_split_no = 0;
656  splits = xaccAccountGetSplitList(acc);
657  split_count = g_list_length (splits);
658  for (node = splits; node; node = node->next)
659  {
660  Split *split = node->data;
661 
662  PINFO("Start processing split %d of %d",
663  curr_split_no + 1, split_count);
664 
665  if (curr_split_no % 100 == 0)
666  {
667  char *progress_msg = g_strdup_printf (message, str, curr_split_no, split_count);
668  (percentagefunc)(progress_msg, (100 * curr_split_no) / split_count);
669  g_free (progress_msg);
670  }
671 
672  if (split)
673  // If gncScrubBusinessSplit returns true, a split was deleted and hence
674  // The account split list has become invalid, so we need to start over
675  if (gncScrubBusinessSplit (split))
676  goto restart;
677 
678  PINFO("Finished processing split %d of %d",
679  curr_split_no + 1, split_count);
680  curr_split_no++;
681  }
683  (percentagefunc)(NULL, -1.0);
684  LEAVE ("(acc=%s)", str);
685 }
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3603
#define PINFO(format, args...)
Definition: qoflog.h:244
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:2884
#define ENTER(format, args...)
Definition: qoflog.h:256
GList SplitList
Definition: gnc-engine.h:203
gboolean gncScrubBusinessSplit(Split *split)
gboolean xaccAccountIsAPARType(GNCAccountType t)
Definition: Account.c:4111
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1143
#define LEAVE(format, args...)
Definition: qoflog.h:266
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:2906
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1184

◆ gncScrubBusinessAccountTree()

void gncScrubBusinessAccountTree ( Account acc,
QofPercentageFunc  percentagefunc 
)

The gncScrubBusinessAccountTreeLots() function will call gncScrubBusinessAccount() on the given account and its sub accounts.

Definition at line 709 of file ScrubBusiness.c.

710 {
711  if (!acc) return;
712 
713  gnc_account_foreach_descendant(acc, lot_scrub_cb, percentagefunc);
714  gncScrubBusinessAccount (acc, percentagefunc);
715 }
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2833
void gncScrubBusinessAccount(Account *acc, QofPercentageFunc percentagefunc)

◆ 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)
Definition: Scrub2.c:412
#define PINFO(format, args...)
Definition: qoflog.h:244
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1658
#define ENTER(format, args...)
Definition: qoflog.h:256
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Definition: gnc-lot.c:574
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:368
void xaccTransDestroy(Transaction *trans)
Definition: Transaction.c:1378
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1143
#define LEAVE(format, args...)
Definition: qoflog.h:266
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:311
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1184

◆ 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)
Definition: Transaction.c:2303
time64 xaccTransGetDate(const Transaction *trans)
Definition: Transaction.c:2219
#define PINFO(format, args...)
Definition: qoflog.h:244
gboolean xaccSplitDestroy(Split *split)
Definition: Split.c:1269
gboolean gnc_numeric_zero_p(gnc_numeric a)
Definition: gnc-numeric.c:173
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1658
#define ENTER(format, args...)
Definition: qoflog.h:256
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Definition: gncInvoice.c:1207
#define PWARN(format, args...)
Definition: qoflog.h:238
char * qof_print_date(time64 t)
Definition: gnc-date.c:917
#define TXN_TYPE_NONE
Definition: Transaction.h:119
void xaccSplitSetMemo(Split *split, const char *memo)
Definition: Split.c:1529
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2188
const char * xaccTransGetReadOnly(const Transaction *trans)
Definition: Transaction.c:2314
time64 xaccTransGetDateEntered(const Transaction *trans)
Definition: Transaction.c:2226
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Definition: Transaction.c:2525
#define LEAVE(format, args...)
Definition: qoflog.h:266
gint64 time64
Definition: gnc-date.h:79
gchar * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition: gnc-date.c:390
GNCLot * xaccSplitGetLot(const Split *split)
Definition: Split.c:1708
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1742

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

Loop over all splits, and make sure that every split belongs to some 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)
Definition: Account.c:3603
gboolean gnc_numeric_zero_p(gnc_numeric a)
Definition: gnc-numeric.c:173
#define ENTER(format, args...)
Definition: qoflog.h:256
GList SplitList
Definition: gnc-engine.h:203
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Definition: Transaction.c:2525
gboolean xaccSplitAssign(Split *split)
Definition: cap-gains.c:582
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1143
#define LEAVE(format, args...)
Definition: qoflog.h:266
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:2906
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1184

◆ xaccAccountScrubCommodity()

void xaccAccountScrubCommodity ( Account account)

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

Definition at line 1196 of file Scrub.c.

1197 {
1198  gnc_commodity *commodity;
1199 
1200  if (!account) return;
1201  if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return;
1202 
1203  commodity = xaccAccountGetCommodity (account);
1204  if (commodity) return;
1205 
1206  /* Use the 'obsolete' routines to try to figure out what the
1207  * account commodity should have been. */
1208  commodity = xaccAccountGetCommodity (account);
1209  if (commodity)
1210  {
1211  xaccAccountSetCommodity (account, commodity);
1212  return;
1213  }
1214 
1215  commodity = DxaccAccountGetCurrency (account);
1216  if (commodity)
1217  {
1218  xaccAccountSetCommodity (account, commodity);
1219  return;
1220  }
1221 
1222  PERR ("Account \"%s\" does not have a commodity!",
1223  xaccAccountGetName(account));
1224 }
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition: Account.c:3014
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:2884
#define PERR(format, args...)
Definition: qoflog.h:232
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3034
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:2906
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2264

◆ xaccAccountScrubKvp()

void xaccAccountScrubKvp ( Account account)

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

Definition at line 1336 of file Scrub.c.

1337 {
1338  const gchar *str;
1339  gchar *str2;
1340  kvp_frame *frame;
1341 
1342  if (!account) return;
1343 
1344  str = kvp_frame_get_string(account->inst.kvp_data, "notes");
1345  if (str)
1346  {
1347  str2 = g_strstrip(g_strdup(str));
1348  if (strlen(str2) == 0)
1349  kvp_frame_set_slot_nc (account->inst.kvp_data, "notes", NULL);
1350  g_free(str2);
1351  }
1352 
1353  str = kvp_frame_get_string(account->inst.kvp_data, "placeholder");
1354  if (str && strcmp(str, "false") == 0)
1355  kvp_frame_set_slot_nc (account->inst.kvp_data, "placeholder", NULL);
1356 
1357  frame = kvp_frame_get_frame(account->inst.kvp_data, "hbci");
1358  if (frame && kvp_frame_is_empty(frame))
1359  {
1360  kvp_frame_set_frame_nc(account->inst.kvp_data, "hbci", NULL);
1361  }
1362 }
gboolean kvp_frame_is_empty(const KvpFrame *frame)
Definition: kvp_frame.c:134
#define kvp_frame
Definition: kvp_frame.h:106
void kvp_frame_set_slot_nc(KvpFrame *frame, const gchar *key, KvpValue *value)
KvpFrame * kvp_frame_get_frame(const KvpFrame *frame, const gchar *path)

◆ 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
Definition: gnc-engine.h:201
gboolean xaccAccountHasTrades(const Account *acc)
Definition: cap-gains.c:79
void xaccAccountAssignLots(Account *acc)
Definition: Scrub2.c:59
#define ENTER(format, args...)
Definition: qoflog.h:256
LotList * xaccAccountGetLotList(const Account *acc)
Definition: Account.c:3630
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1143
#define LEAVE(format, args...)
Definition: qoflog.h:266
gboolean xaccScrubLot(GNCLot *lot)
Definition: Scrub3.c:85
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:2906
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1184

◆ xaccAccountScrubOrphans()

void xaccAccountScrubOrphans ( Account acc,
QofPercentageFunc  percentagefunc 
)

The xaccAccountScrubOrphans() method performs this scrub only for the indicated account, and not for any of its children.

Definition at line 102 of file Scrub.c.

103 {
104  GList *node, *splits;
105  const char *str;
106  const char *message = _( "Looking for orphans in account %s: %u of %u");
107  guint total_splits = 0;
108  guint current_split = 0;
109 
110  if (!acc) return;
111 
112  str = xaccAccountGetName (acc);
113  str = str ? str : "(null)";
114  PINFO ("Looking for orphans in account %s \n", str);
115  splits = xaccAccountGetSplitList(acc);
116  total_splits = g_list_length (splits);
117 
118  for (node = splits; node; node = node->next)
119  {
120  Split *split = node->data;
121 
122  if (current_split % 100 == 0)
123  {
124  char *progress_msg = g_strdup_printf (message, str, current_split, total_splits);
125  (percentagefunc)(progress_msg, (100 * current_split) / total_splits);
126  g_free (progress_msg);
127  }
128 
129  TransScrubOrphansFast (xaccSplitGetParent (split),
130  gnc_account_get_root (acc));
131  current_split++;
132  }
133  (percentagefunc)(NULL, -1.0);
134 }
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3603
#define PINFO(format, args...)
Definition: qoflog.h:244
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1658
Account * gnc_account_get_root(Account *acc)
Definition: Account.c:2505
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:2906

◆ 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 1257 of file Scrub.c.

1258 {
1259  if (!acc) return;
1260 
1261  xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, NULL);
1262 
1263  scrub_account_commodity_helper (acc, NULL);
1264  gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, NULL);
1265 }
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2833

◆ xaccAccountTreeScrubOrphans()

void xaccAccountTreeScrubOrphans ( Account acc,
QofPercentageFunc  percentagefunc 
)

The xaccAccountTreeScrubOrphans() method performs this scrub for the indicated account and its children.

Definition at line 62 of file Scrub.c.

63 {
64  if (!acc) return;
65 
66  xaccAccountScrubOrphans (acc, percentagefunc);
68  (AccountCb)xaccAccountScrubOrphans, percentagefunc);
69 }
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2833
void xaccAccountScrubOrphans(Account *acc, QofPercentageFunc percentagefunc)
Definition: Scrub.c:102

◆ 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 1314 of file Scrub.c.

1315 {
1316  gboolean new_style = FALSE;
1317  ENTER(" ");
1318 
1319  if (!root || !table)
1320  {
1321  LEAVE("Oops");
1322  return;
1323  }
1324 
1325  gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
1326 
1327  move_quote_source(root, GINT_TO_POINTER(new_style));
1328  gnc_account_foreach_descendant (root, move_quote_source,
1329  GINT_TO_POINTER(new_style));
1330  LEAVE("Migration done");
1331 }
gboolean gnc_commodity_table_foreach_commodity(const gnc_commodity_table *table, gboolean(*f)(gnc_commodity *cm, gpointer user_data), gpointer user_data)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2833
#define ENTER(format, args...)
Definition: qoflog.h:256
#define LEAVE(format, args...)
Definition: qoflog.h:266

◆ 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)
Definition: gnc-numeric.c:1383
gboolean gnc_numeric_zero_p(gnc_numeric a)
Definition: gnc-numeric.c:173
#define PERR(format, args...)
Definition: qoflog.h:232
#define ENTER(format, args...)
Definition: qoflog.h:256
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:368
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
Definition: cap-gains.c:365
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Definition: Transaction.c:2525
gboolean gnc_lot_is_closed(GNCLot *lot)
Definition: gnc-lot.c:301
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1143
#define LEAVE(format, args...)
Definition: qoflog.h:266
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:311
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:2906
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1184
GNCPolicy * gnc_account_get_policy(Account *acc)
Definition: Account.c:1743
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:404

◆ 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", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
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", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
239 }
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Definition: gnc-numeric.c:304
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Definition: gnc-numeric.c:1383
#define PINFO(format, args...)
Definition: qoflog.h:244
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
Definition: cap-gains.c:680
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Definition: gnc-numeric.c:378
#define PERR(format, args...)
Definition: qoflog.h:232
#define ENTER(format, args...)
Definition: qoflog.h:256
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:368
#define PWARN(format, args...)
Definition: qoflog.h:238
GList SplitList
Definition: gnc-engine.h:203
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:348
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2188
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
gboolean gnc_lot_is_closed(GNCLot *lot)
Definition: gnc-lot.c:301
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1748
#define LEAVE(format, args...)
Definition: qoflog.h:266
KvpFrame * gnc_lot_get_slots(const GNCLot *lot)
Definition: gnc-lot.c:342
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:242
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)

◆ 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)
Definition: Scrub2.c:412
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Definition: gnc-numeric.c:1383
void xaccLotFill(GNCLot *lot)
Definition: Scrub2.c:97
#define PINFO(format, args...)
Definition: qoflog.h:244
gboolean gnc_numeric_zero_p(gnc_numeric a)
Definition: gnc-numeric.c:173
#define ENTER(format, args...)
Definition: qoflog.h:256
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:368
GList SplitList
Definition: gnc-engine.h:203
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:348
void xaccLotScrubDoubleBalance(GNCLot *lot)
Definition: Scrub2.c:165
gboolean gnc_numeric_positive_p(gnc_numeric a)
Definition: gnc-numeric.c:221
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1143
#define LEAVE(format, args...)
Definition: qoflog.h:266
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:311
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1184
GNCPolicy * gnc_account_get_policy(Account *acc)
Definition: Account.c:1743
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:404

◆ xaccScrubMergeLotSubSplits()

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 at line 412 of file Scrub2.c.

413 {
414  gboolean rc = FALSE;
415  SplitList *node;
416 
417  if (!lot) return FALSE;
418 
419  ENTER (" ");
420 restart:
421  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
422  {
423  Split *s = node->data;
424  if (!xaccScrubMergeSubSplits(s, strict)) continue;
425 
426  rc = TRUE;
427  goto restart;
428  }
429  LEAVE (" splits merged=%d", rc);
430  return rc;
431 }
#define ENTER(format, args...)
Definition: qoflog.h:256
GList SplitList
Definition: gnc-engine.h:203
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:348
gboolean xaccScrubMergeSubSplits(Split *split, gboolean strict)
Definition: Scrub2.c:348
#define LEAVE(format, args...)
Definition: qoflog.h:266

◆ 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 348 of file Scrub2.c.

349 {
350  gboolean rc = FALSE;
351  Transaction *txn;
352  SplitList *node;
353  GNCLot *lot;
354  const GncGUID *guid;
355 
356  if (strict && (FALSE == is_subsplit (split))) return FALSE;
357 
358  txn = split->parent;
359 
360  // Don't mess with splits from an invoice transaction
361  // Those are the responsibility of the business code
362  if (gncInvoiceGetInvoiceFromTxn (txn)) return FALSE;
363 
364  lot = xaccSplitGetLot (split);
365 
366  ENTER ("(Lot=%s)", gnc_lot_get_title(lot));
367 restart:
368  for (node = txn->splits; node; node = node->next)
369  {
370  Split *s = node->data;
371  if (xaccSplitGetLot (s) != lot) continue;
372  if (s == split) continue;
373  if (qof_instance_get_destroying(s)) continue;
374 
375  // Don't mess with splits from an invoice transaction
376  // Those are the responsibility of the business code
377  if (gncInvoiceGetInvoiceFromTxn (s->parent)) return FALSE;
378 
379  if (strict)
380  {
381  /* OK, this split is in the same lot (and thus same account)
382  * as the indicated split. Make sure it is really a subsplit
383  * of the split we started with. It's possible to have two
384  * splits in the same lot and transaction that are not subsplits
385  * of each other, the test-period test suite does this, for
386  * example. Only worry about adjacent sub-splits. By
387  * repeatedly merging adjacent subsplits, we'll get the non-
388  * adjacent ones too. */
389  guid = qof_instance_get_guid(s);
390  if (gnc_kvp_bag_find_by_guid (split->inst.kvp_data, "lot-split",
391  "peer_guid", guid) == NULL)
392  continue;
393  }
394 
395  merge_splits (split, s);
396  rc = TRUE;
397  goto restart;
398  }
399  if (rc && gnc_numeric_zero_p (split->amount))
400  {
401  time64 pdate = xaccTransGetDate (txn);
402  gchar *pdatestr = gnc_ctime (&pdate);
403  PWARN ("Result of merge has zero amt!");
404  PWARN ("Transaction details - posted date %s - description %s", pdatestr, xaccTransGetDescription(txn));
405  g_free (pdatestr);
406  }
407  LEAVE (" splits merged=%d", rc);
408  return rc;
409 }
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Definition: qofinstance.c:473
time64 xaccTransGetDate(const Transaction *trans)
Definition: Transaction.c:2219
gboolean qof_instance_get_destroying(gconstpointer ptr)
Definition: qofinstance.c:660
Definition: guid.h:54
gboolean gnc_numeric_zero_p(gnc_numeric a)
Definition: gnc-numeric.c:173
#define ENTER(format, args...)
Definition: qoflog.h:256
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Definition: gncInvoice.c:1207
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:368
#define PWARN(format, args...)
Definition: qoflog.h:238
GList SplitList
Definition: gnc-engine.h:203
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2188
KvpFrame * gnc_kvp_bag_find_by_guid(KvpFrame *root, const char *path, const char *guid_name, const GncGUID *desired_guid)
Definition: kvp-util.c:96
#define LEAVE(format, args...)
Definition: qoflog.h:266
gint64 time64
Definition: gnc-date.h:79
gchar * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition: gnc-date.c:390
GNCLot * xaccSplitGetLot(const Split *split)
Definition: Split.c:1708

◆ 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 190 of file Scrub.c.

191 {
192  Account *account;
193  Transaction *trans;
194  gnc_numeric value, amount;
195  gnc_commodity *currency, *acc_commodity;
196  int scu;
197 
198  if (!split) return;
199  ENTER ("(split=%p)", split);
200 
201  trans = xaccSplitGetParent (split);
202  if (!trans)
203  {
204  LEAVE("no trans");
205  return;
206  }
207 
208  account = xaccSplitGetAccount (split);
209 
210  /* If there's no account, this split is an orphan.
211  * We need to fix that first, before proceeding.
212  */
213  if (!account)
214  {
215  xaccTransScrubOrphans (trans);
216  account = xaccSplitGetAccount (split);
217  }
218 
219  /* Grrr... the register gnc_split_register_load() line 203 of
220  * src/register/ledger-core/split-register-load.c will create
221  * free-floating bogus transactions. Ignore these for now ...
222  */
223  if (!account)
224  {
225  PINFO ("Free Floating Transaction!");
226  LEAVE ("no account");
227  return;
228  }
229 
230  /* Split amounts and values should be valid numbers */
231  value = xaccSplitGetValue (split);
232  if (gnc_numeric_check (value))
233  {
234  value = gnc_numeric_zero();
235  xaccSplitSetValue (split, value);
236  }
237 
238  amount = xaccSplitGetAmount (split);
239  if (gnc_numeric_check (amount))
240  {
241  amount = gnc_numeric_zero();
242  xaccSplitSetAmount (split, amount);
243  }
244 
245  currency = xaccTransGetCurrency (trans);
246 
247  /* If the account doesn't have a commodity,
248  * we should attempt to fix that first.
249  */
250  acc_commodity = xaccAccountGetCommodity(account);
251  if (!acc_commodity)
252  {
253  xaccAccountScrubCommodity (account);
254  }
255  if (!acc_commodity || !gnc_commodity_equiv(acc_commodity, currency))
256  {
257  LEAVE ("(split=%p) inequiv currency", split);
258  return;
259  }
260 
261  scu = MIN (xaccAccountGetCommoditySCU (account),
262  gnc_commodity_get_fraction (currency));
263 
264  if (gnc_numeric_same (amount, value, scu, GNC_HOW_RND_ROUND_HALF_UP))
265  {
266  LEAVE("(split=%p) different values", split);
267  return;
268  }
269 
270  /*
271  * This will be hit every time you answer yes to the dialog "The
272  * current transaction has changed. Would you like to record it.
273  */
274  PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
275  " old amount %s %s, new amount %s",
276  trans->description, split->memo,
278  gnc_commodity_get_mnemonic (currency),
280 
281  xaccTransBeginEdit (trans);
282  xaccSplitSetAmount (split, value);
283  xaccTransCommitEdit (trans);
284  LEAVE ("(split=%p)", split);
285 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1074
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Definition: gnc-numeric.c:1383
int gnc_commodity_get_fraction(const gnc_commodity *cm)
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
#define PINFO(format, args...)
Definition: qoflog.h:244
void xaccAccountScrubCommodity(Account *account)
Definition: Scrub.c:1196
int xaccAccountGetCommoditySCU(const Account *acc)
Definition: Account.c:2333
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1658
#define ENTER(format, args...)
Definition: qoflog.h:256
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1042
void xaccTransScrubOrphans(Transaction *trans)
Definition: Scrub.c:138
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1555
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1356
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1748
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:732
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3034
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1268
#define LEAVE(format, args...)
Definition: qoflog.h:266
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Definition: gnc-numeric.c:83
int gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Definition: gnc-numeric.c:360
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1742

◆ 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 1079 of file Scrub.c.

1080 {
1081  SplitList *node;
1082  gnc_commodity *currency;
1083 
1084  if (!trans) return;
1085 
1086  /* If there are any orphaned splits in a transaction, then the
1087  * this routine will fail. Therefore, we want to make sure that
1088  * there are no orphans (splits without parent account).
1089  */
1090  xaccTransScrubOrphans (trans);
1091 
1092  currency = xaccTransGetCurrency (trans);
1093  if (currency && gnc_commodity_is_currency(currency)) return;
1094 
1095  currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans));
1096  if (currency)
1097  {
1098  xaccTransBeginEdit (trans);
1099  xaccTransSetCurrency (trans, currency);
1100  xaccTransCommitEdit (trans);
1101  }
1102  else
1103  {
1104  if (NULL == trans->splits)
1105  {
1106  PWARN ("Transaction \"%s\" has no splits in it!", trans->description);
1107  }
1108  else
1109  {
1110  SplitList *node;
1111  char guid_str[GUID_ENCODING_LENGTH + 1];
1112  guid_to_string_buff(xaccTransGetGUID(trans), guid_str);
1113  PWARN ("no common transaction currency found for trans=\"%s\" (%s);",
1114  trans->description, guid_str);
1115 
1116  for (node = trans->splits; node; node = node->next)
1117  {
1118  Split *split = node->data;
1119  if (NULL == split->acc)
1120  {
1121  PWARN (" split=\"%s\" is not in any account!", split->memo);
1122  }
1123  else
1124  {
1125  gnc_commodity *currency = xaccAccountGetCommodity(split->acc);
1126  PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"",
1127  split->memo, xaccAccountGetName(split->acc),
1128  gnc_commodity_get_mnemonic(currency));
1129 
1130  xaccTransBeginEdit (trans);
1131  xaccTransSetCurrency (trans, currency);
1132  xaccTransCommitEdit (trans);
1133  return;
1134  }
1135  }
1136  }
1137  return;
1138  }
1139 
1140  for (node = trans->splits; node; node = node->next)
1141  {
1142  Split *sp = node->data;
1143 
1145  xaccSplitGetValue (sp)))
1146  {
1147  gnc_commodity *acc_currency;
1148 
1149  acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : NULL;
1150  if (acc_currency == currency)
1151  {
1152  /* This Split needs fixing: The transaction-currency equals
1153  * the account-currency/commodity, but the amount/values are
1154  * inequal i.e. they still correspond to the security
1155  * (amount) and the currency (value). In the new model, the
1156  * value is the amount in the account-commodity -- so it
1157  * needs to be set to equal the amount (since the
1158  * account-currency doesn't exist anymore).
1159  *
1160  * Note: Nevertheless we lose some information here. Namely,
1161  * the information that the 'amount' in 'account-old-security'
1162  * was worth 'value' in 'account-old-currency'. Maybe it would
1163  * be better to store that information in the price database?
1164  * But then, for old currency transactions there is still the
1165  * 'other' transaction, which is going to keep that
1166  * information. So I don't bother with that here. -- cstim,
1167  * 2002/11/20. */
1168 
1169  PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
1170  " old amount %s %s, new amount %s",
1171  trans->description, sp->memo,
1173  gnc_commodity_get_mnemonic (currency),
1175  xaccTransBeginEdit (trans);
1177  xaccTransCommitEdit (trans);
1178  }
1179  /*else
1180  {
1181  PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
1182  xaccSplitGetMemo (sp),
1183  gnc_num_dbg_to_string (amount),
1184  gnc_commodity_get_mnemonic (currency),
1185  gnc_num_dbg_to_string (value),
1186  gnc_commodity_get_mnemonic (acc_currency));
1187  }*/
1188  }
1189  }
1190 
1191 }
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Definition: gnc-numeric.c:304
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Definition: gnc-numeric.c:1383
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
QofBook * qof_instance_get_book(gconstpointer inst)
Definition: qofinstance.c:548
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1327
#define PWARN(format, args...)
Definition: qoflog.h:238
GList SplitList
Definition: gnc-engine.h:203
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1042
#define GUID_ENCODING_LENGTH
Definition: guid.h:71
void xaccTransScrubOrphans(Transaction *trans)
Definition: Scrub.c:138
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1555
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1356
#define xaccTransGetGUID(X)
Definition: Transaction.h:764
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1748
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3034
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1268
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:2906
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1742

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

Correct transaction imbalances.

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

Definition at line 802 of file Scrub.c.

804 {
805  gnc_numeric imbalance;
806 
807  if (!trans) return;
808 
809  ENTER ("()");
810 
811  /* Must look for orphan splits even if there is no imbalance. */
812  xaccTransScrubSplits (trans);
813 
814  /* Return immediately if things are balanced. */
815  if (xaccTransIsBalanced (trans))
816  {
817  LEAVE ("transaction is balanced");
818  return;
819  }
820 
821  if (! xaccTransUseTradingAccounts (trans))
822  {
823  gnc_transaction_balance_no_trading (trans, root, account);
824  LEAVE ("transaction balanced, no trading accounts");
825  return;
826  }
827 
828  imbalance = gnc_transaction_adjust_trading_splits (trans, root);
829 
830  /* Balance the value, ignoring existing trading splits */
831  if (! gnc_numeric_zero_p (imbalance))
832  {
833  PINFO ("Value unbalanced transaction");
834 
835  add_balance_split (trans, imbalance, root, account);
836  }
837 
838  gnc_transaction_balance_trading (trans, root);
840  {
841  LEAVE ("()");
842  return;
843  }
844  /* If the transaction is still not balanced, it's probably because there
845  are splits with zero amount and non-zero value. These are usually
846  realized gain/loss splits. Add a reversing split for each of them to
847  balance the value. */
848 
849  gnc_transaction_balance_trading_more_splits (trans, root);
851  PERR("Balancing currencies unbalanced value");
852 
853 }
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Definition: Transaction.c:935
#define PINFO(format, args...)
Definition: qoflog.h:244
gboolean gnc_numeric_zero_p(gnc_numeric a)
Definition: gnc-numeric.c:173
gboolean xaccTransIsBalanced(const Transaction *trans)
Definition: Transaction.c:1044
#define PERR(format, args...)
Definition: qoflog.h:232
#define ENTER(format, args...)
Definition: qoflog.h:256
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
Definition: Transaction.c:956
void xaccTransScrubSplits(Transaction *trans)
Definition: Transaction.c:2618
#define LEAVE(format, args...)
Definition: qoflog.h:266

◆ xaccTransScrubOrphans()

void xaccTransScrubOrphans ( Transaction *  trans)

The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.

Definition at line 138 of file Scrub.c.

139 {
140  SplitList *node;
141  QofBook *book = NULL;
142  Account *root = NULL;
143 
144  if (!trans) return;
145 
146  for (node = trans->splits; node; node = node->next)
147  {
148  Split *split = node->data;
149 
150  if (split->acc)
151  {
152  TransScrubOrphansFast (trans, gnc_account_get_root(split->acc));
153  return;
154  }
155  }
156 
157  /* If we got to here, then *none* of the splits belonged to an
158  * account. Not a happy situation. We should dig an account
159  * out of the book the transaction belongs to.
160  * XXX we should probably *always* to this, instead of the above loop!
161  */
162  PINFO ("Free Floating Transaction!");
163  book = xaccTransGetBook (trans);
164  root = gnc_book_get_root_account (book);
165  TransScrubOrphansFast (trans, root);
166 }
#define PINFO(format, args...)
Definition: qoflog.h:244
GList SplitList
Definition: gnc-engine.h:203
#define xaccTransGetBook(X)
Definition: Transaction.h:762
Account * gnc_account_get_root(Account *acc)
Definition: Account.c:2505

◆ 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 1404 of file Scrub.c.

1405 {
1406  time64 orig = xaccTransGetDate(trans);
1407  GDate date = xaccTransGetDatePostedGDate(trans);
1408  Timespec ts = gdate_to_timespec(date);
1409  if (orig && orig != ts.tv_sec)
1410  {
1411  /* xaccTransSetDatePostedTS handles committing the change. */
1412  xaccTransSetDatePostedTS(trans, &ts);
1413  }
1414 }
time64 xaccTransGetDate(const Transaction *trans)
Definition: Transaction.c:2219
gint64 time64
Definition: gnc-date.h:79
Timespec gdate_to_timespec(GDate d)
Definition: gnc-date.c:1688
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Definition: Transaction.c:2254
void xaccTransSetDatePostedTS(Transaction *trans, const Timespec *ts)
Definition: Transaction.c:1946

◆ xaccTransScrubSplits()

void xaccTransScrubSplits ( Transaction *  trans)

The xacc*ScrubSplits() calls xaccSplitScrub() on each split in the respective structure: transaction, account, account & it's children, account-group.

Definition at line 2618 of file Transaction.c.

2619 {
2620  gnc_commodity *currency;
2621 
2622  if (!trans) return;
2623 
2624  xaccTransBeginEdit(trans);
2625  /* The split scrub expects the transaction to have a currency! */
2626  currency = xaccTransGetCurrency (trans);
2627  if (!currency)
2628  PERR ("Transaction doesn't have a currency!");
2629 
2630  FOR_EACH_SPLIT(trans, xaccSplitScrub(s));
2631  xaccTransCommitEdit(trans);
2632 }
#define PERR(format, args...)
Definition: qoflog.h:232
void xaccSplitScrub(Split *split)
Definition: Scrub.c:190
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1555
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1356
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1268