GnuCash c935c2f+
Loading...
Searching...
No Matches
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.
 
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.
 
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.
 
void xaccAccountScrubCommodity (Account *account)
 The xaccAccountScrubCommodity method fixed accounts without a commodity by using the old account currency and security.
 
void xaccAccountTreeScrubCommodities (Account *acc)
 The xaccAccountTreeScrubCommodities will scrub the currency/commodity of all accounts & transactions in the specified account or any child account.
 
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.
 
void xaccAccountScrubKvp (Account *account)
 Removes empty "notes", "placeholder", and "hbci" KVP slots from Accounts.
 
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.
 

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.
 
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.
 
void xaccLotScrubDoubleBalance (GNCLot *lot)
 The xaccLotScrubDoubleBalance() routine examines the indicated lot.
 
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.
 
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.
 
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).
 
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.
 
gboolean gncScrubBusinessSplit (Split *split)
 The gncScrubBusinessSplit() function will fix all issues found with the given split.
 
void gncScrubBusinessAccountLots (Account *acc, QofPercentageFunc percentagefunc)
 The gncScrubBusinessAccountLots() function will call gncScrubBusinessLot() on each lot in the given account.
 
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).
 
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

◆ gnc_get_abort_scrub()

gboolean gnc_get_abort_scrub ( void  )

Definition at line 81 of file Scrub.cpp.

82{
83 return abort_now;
84}

◆ gnc_get_ongoing_scrub()

gboolean gnc_get_ongoing_scrub ( void  )

The gnc_get_ongoing_scrub () method returns TRUE if a scrub operation is ongoing.

Definition at line 87 of file Scrub.cpp.

88{
89 return scrub_depth > 0;
90}

◆ gnc_set_abort_scrub()

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.

Definition at line 75 of file Scrub.cpp.

76{
77 abort_now = abort;
78}

◆ 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:3267
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition Account.cpp:4527
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...

◆ 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)
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}
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition Account.cpp:3289
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition Account.cpp:1516
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition Account.cpp:1475
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition Account.cpp:3975
GList LotList
GList of GNCLots.
Definition gnc-engine.h:205
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gboolean gncScrubBusinessLot(GNCLot *lot)
The gncScrubBusinessLot() function makes sure that the indicated lot has all the correct properties r...

◆ gncScrubBusinessAccountSplits()

void gncScrubBusinessAccountSplits ( Account acc,
QofPercentageFunc  percentagefunc 
)

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

Definition at line 674 of file ScrubBusiness.c.

675{
676 SplitList *splits, *node;
677 gint split_count = 0;
678 gint curr_split_no;
679 const gchar *str;
680 const char *message = _( "Checking business splits in account %s: %u of %u");
681
682 if (!acc) return;
683
684 if (gnc_get_abort_scrub())
685 (percentagefunc)(NULL, -1.0);
686
687 if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
688
689 str = xaccAccountGetName(acc);
690 str = str ? str : "(null)";
691
692 ENTER ("(acc=%s)", str);
693 PINFO ("Cleaning up superfluous lot links in account %s\n", str);
695
696restart:
697 curr_split_no = 0;
698 splits = xaccAccountGetSplitList(acc);
699 split_count = xaccAccountGetSplitsSize (acc);
700 for (node = splits; node; node = node->next)
701 {
702 Split *split = node->data;
703
704 PINFO("Start processing split %d of %d",
705 curr_split_no + 1, split_count);
706
707 if (gnc_get_abort_scrub ())
708 break;
709
710 if (curr_split_no % 100 == 0)
711 {
712 char *progress_msg = g_strdup_printf (message, str, curr_split_no, split_count);
713 (percentagefunc)(progress_msg, (100 * curr_split_no) / split_count);
714 g_free (progress_msg);
715 }
716
717 if (split)
718 // If gncScrubBusinessSplit returns true, a split was deleted and hence
719 // The account split list has become invalid, so we need to start over
720 if (gncScrubBusinessSplit (split))
721 goto restart;
722
723 PINFO("Finished processing split %d of %d",
724 curr_split_no + 1, split_count);
725 curr_split_no++;
726 }
727 g_list_free (splits);
729 (percentagefunc)(NULL, -1.0);
730 LEAVE ("(acc=%s)", str);
731}
GList SplitList
GList of Split.
Definition gnc-engine.h:207
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account.
Definition Account.cpp:3949
gboolean gncScrubBusinessSplit(Split *split)
The gncScrubBusinessSplit() function will fix all issues found with the given split.

◆ gncScrubBusinessAccountTree()

void gncScrubBusinessAccountTree ( Account acc,
QofPercentageFunc  percentagefunc 
)

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

Definition at line 755 of file ScrubBusiness.c.

756{
757 if (!acc) return;
758
759 gnc_account_foreach_descendant(acc, lot_scrub_cb, percentagefunc);
760 gncScrubBusinessAccount (acc, percentagefunc);
761}
void gncScrubBusinessAccount(Account *acc, QofPercentageFunc percentagefunc)
The gncScrubBusinessAccount() function will call all scrub functions relevant for a given account on ...

◆ 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}
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition gnc-lot.cpp:377
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Convenience routine to identify the earliest date in the lot.
Definition gnc-lot.cpp:658
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
The xaccScrubMergeLotSubSplits() routine does the same as the xaccScrubMergSubSplits,...
Definition Scrub2.cpp:390
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
STRUCTS.

◆ 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}
char * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition gnc-date.cpp:256
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
char * qof_print_date(time64 t)
Convenience; calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:610
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
char xaccTransGetTxnType(Transaction *trans)
Returns the Transaction Type: note this type will be derived from the transaction splits,...
void xaccTransSetTxnType(Transaction *trans, char type)
Set the Transaction Type: note the type will be saved into the Transaction kvp property as a backward...
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
#define TXN_TYPE_NONE
No transaction type
time64 xaccTransGetDateEntered(const Transaction *trans)
Retrieve the date of when the transaction was entered.
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Given a transaction, find and return the Invoice.
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
void gnc_lot_remove_split(GNCLot *lot, Split *split)
Adds a split from this lot.
Definition gnc-lot.cpp:631
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void gncOwnerAttachToLot(const GncOwner *owner, GNCLot *lot)
Attach an owner to a lot.
Definition gncOwner.c:622
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition Split.cpp:1506
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
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:1920
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.

◆ 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
66restart_loop:
67 for (auto split : xaccAccountGetSplits (acc))
68 {
69 /* If already in lot, then no-op */
70 if (split->lot) continue;
71
72 /* Skip stock splits */
73 if (xaccSplitIsStockSplit(split)) continue;
74
75 /* Skip voided transactions */
76 if (gnc_numeric_zero_p (split->amount) &&
77 xaccTransGetVoidStatus(split->parent)) continue;
78
79 if (xaccSplitAssign (split)) goto restart_loop;
80 }
82 LEAVE ("acc=%s", xaccAccountGetName(acc));
83}
gboolean xaccSplitAssign(Split *split)
The`xaccSplitAssign() routine will take the indicated split and, if it doesn't already belong to a lo...
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
Definition Split.cpp:2078

◆ xaccAccountScrubColorNotSet()

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.

Definition at line 1415 of file Scrub.cpp.

1416{
1417 GValue value_s = G_VALUE_INIT;
1418 gboolean already_scrubbed;
1419
1420 // get the run-once value
1421 qof_instance_get_kvp (QOF_INSTANCE (book), &value_s, 1, "remove-color-not-set-slots");
1422
1423 already_scrubbed = (G_VALUE_HOLDS_STRING (&value_s) &&
1424 !g_strcmp0 (g_value_get_string (&value_s), "true"));
1425 g_value_unset (&value_s);
1426
1427 if (already_scrubbed)
1428 return;
1429 else
1430 {
1431 GValue value_b = G_VALUE_INIT;
1432 Account *root = gnc_book_get_root_account (book);
1433 GList *accts = gnc_account_get_descendants_sorted (root);
1434 GList *ptr;
1435
1436 for (ptr = accts; ptr; ptr = g_list_next (ptr))
1437 {
1438 auto acct = GNC_ACCOUNT(ptr->data);
1439 auto color = xaccAccountGetColor (acct);
1440
1441 if (g_strcmp0 (color, "Not Set") == 0)
1442 xaccAccountSetColor (acct, "");
1443 }
1444 g_list_free (accts);
1445
1446 g_value_init (&value_b, G_TYPE_BOOLEAN);
1447 g_value_set_boolean (&value_b, TRUE);
1448
1449 // set the run-once value
1450 qof_instance_set_kvp (QOF_INSTANCE (book), &value_b, 1, "remove-color-not-set-slots");
1451 g_value_unset (&value_b);
1452 }
1453}
void xaccAccountSetColor(Account *acc, const char *str)
Set the account's Color.
Definition Account.cpp:2613
const char * xaccAccountGetColor(const Account *acc)
Get the account's color.
Definition Account.cpp:3350
GList * gnc_account_get_descendants_sorted(const Account *account)
This function returns a GList containing all the descendants of the specified account,...
Definition Account.cpp:3052
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
Retrieves the contents of a KVP slot into a provided GValue.
void qof_instance_set_kvp(QofInstance *, GValue const *value, unsigned count,...)
Sets a KVP slot to a value from a GValue.

◆ xaccAccountScrubCommodity()

void xaccAccountScrubCommodity ( Account account)

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

Definition at line 1238 of file Scrub.cpp.

1239{
1240 gnc_commodity *commodity;
1241
1242 if (!account) return;
1243 if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return;
1244
1245 commodity = xaccAccountGetCommodity (account);
1246 if (commodity) return;
1247
1248 /* Use the 'obsolete' routines to try to figure out what the
1249 * account commodity should have been. */
1250 commodity = xaccAccountGetCommodity (account);
1251 if (commodity)
1252 {
1253 xaccAccountSetCommodity (account, commodity);
1254 return;
1255 }
1256
1257 commodity = DxaccAccountGetCurrency (account);
1258 if (commodity)
1259 {
1260 xaccAccountSetCommodity (account, commodity);
1261 return;
1262 }
1263
1264 PERR ("Account \"%s\" does not have a commodity!",
1265 xaccAccountGetName(account));
1266}
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account's commodity.
Definition Account.cpp:2678
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition Account.cpp:3396
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244

◆ xaccAccountScrubImbalance()

void xaccAccountScrubImbalance ( Account acc,
QofPercentageFunc  percentagefunc 
)

Definition at line 439 of file Scrub.cpp.

440{
441 AccountScrubImbalance (acc, false, percentagefunc);
442}

◆ xaccAccountScrubKvp()

void xaccAccountScrubKvp ( Account account)

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

Definition at line 1384 of file Scrub.cpp.

1385{
1386 GValue v = G_VALUE_INIT;
1387 gchar *str2;
1388
1389 if (!account) return;
1390 scrub_depth++;
1391
1392 qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "notes");
1393 if (G_VALUE_HOLDS_STRING (&v))
1394 {
1395 str2 = g_strstrip(g_value_dup_string(&v));
1396 if (strlen(str2) == 0)
1397 qof_instance_slot_delete (QOF_INSTANCE (account), "notes");
1398 g_free(str2);
1399 }
1400
1401 qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "placeholder");
1402 if ((G_VALUE_HOLDS_STRING (&v) &&
1403 strcmp(g_value_get_string (&v), "false") == 0) ||
1404 (G_VALUE_HOLDS_BOOLEAN (&v) && ! g_value_get_boolean (&v)))
1405 qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
1406
1407 g_value_unset (&v);
1408 qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
1409 scrub_depth--;
1410}

◆ 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));
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}
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
gboolean xaccScrubLot(GNCLot *lot)
The xaccScrubLot() routine makes sure that the indicated lot is self-consistent and properly balanced...
Definition Scrub3.cpp:85

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

168{
169 AccountScrubOrphans (acc, false, percentagefunc);
170}

◆ xaccAccountScrubSplits()

void xaccAccountScrubSplits ( Account account)

Definition at line 223 of file Scrub.cpp.

224{
225 scrub_depth++;
226 for (auto s : xaccAccountGetSplits (account))
227 {
228 if (abort_now) break;
229 xaccSplitScrub (s);
230 }
231 scrub_depth--;
232}
void xaccSplitScrub(Split *split)
The xaccSplitScrub method ensures that if this split has the same commodity and currency,...
Definition Scrub.cpp:424

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

1304{
1305 if (!acc) return;
1306 scrub_depth++;
1307 xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, nullptr);
1308
1309 scrub_account_commodity_helper (acc, nullptr);
1310 gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, nullptr);
1311 scrub_depth--;
1312}

◆ xaccAccountTreeScrubImbalance()

void xaccAccountTreeScrubImbalance ( Account acc,
QofPercentageFunc  percentagefunc 
)

Definition at line 433 of file Scrub.cpp.

434{
435 AccountScrubImbalance (acc, true, percentagefunc);
436}

◆ xaccAccountTreeScrubLots()

void xaccAccountTreeScrubLots ( Account acc)

Definition at line 190 of file Scrub3.cpp.

191{
192 if (!acc) return;
193
194 gnc_account_foreach_descendant(acc, lot_scrub_cb, nullptr);
196}
void xaccAccountScrubLots(Account *acc)
The xaccAccountScrubLots() routine makes sure that every split in the account is assigned to a lot,...
Definition Scrub3.cpp:159

◆ xaccAccountTreeScrubOrphans()

void xaccAccountTreeScrubOrphans ( Account acc,
QofPercentageFunc  percentagefunc 
)

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

Definition at line 173 of file Scrub.cpp.

174{
175 AccountScrubOrphans (acc, true, percentagefunc);
176}

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

1362{
1363 gboolean new_style = FALSE;
1364 ENTER(" ");
1365
1366 if (!root || !table)
1367 {
1368 LEAVE("Oops");
1369 return;
1370 }
1371 scrub_depth++;
1372 gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
1373
1374 move_quote_source(root, GINT_TO_POINTER(new_style));
1375 gnc_account_foreach_descendant (root, move_quote_source,
1376 GINT_TO_POINTER(new_style));
1377 LEAVE("Migration done");
1378 scrub_depth--;
1379}

◆ xaccAccountTreeScrubSplits()

void xaccAccountTreeScrubSplits ( Account account)

Definition at line 213 of file Scrub.cpp.

214{
215 if (!account) return;
216
217 xaccAccountScrubSplits (account);
218 gnc_account_foreach_descendant(account,
219 (AccountCb)xaccAccountScrubSplits, nullptr);
220}

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

96{
97 Account *acc;
98 Split *split;
99 GNCPolicy *pcy;
100
101 if (!lot) return;
102 acc = gnc_lot_get_account(lot);
103 pcy = gnc_account_get_policy(acc);
104
105 ENTER ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), xaccAccountGetName(acc));
106
107 /* If balance already zero, we have nothing to do. */
108 if (gnc_lot_is_closed (lot))
109 {
110 LEAVE ("Lot Closed (lot=%s, acc=%s)", gnc_lot_get_title(lot),
111 xaccAccountGetName(acc));
112 return;
113 }
114 split = pcy->PolicyGetSplit (pcy, lot);
115 if (!split)
116 {
117 LEAVE ("No Split (lot=%s, acc=%s)", gnc_lot_get_title(lot),
118 xaccAccountGetName(acc));
119 return; /* Handle the common case */
120 }
121
122 /* Reject stock split transactions */
123 if (xaccSplitIsStockSplit(split))
124 {
125 LEAVE ("Stock split transaction (lot=%s, acc=%s)",
126 gnc_lot_get_title(lot), xaccAccountGetName(acc));
127 return;
128 }
129
130 /* Reject voided transactions */
131 if (gnc_numeric_zero_p(split->amount) &&
132 xaccTransGetVoidStatus(split->parent))
133 {
134 LEAVE ("Voided transaction (lot=%s, acc=%s)",
135 gnc_lot_get_title(lot), xaccAccountGetName(acc));
136 return;
137 }
138
140
141 /* Loop until we've filled up the lot, (i.e. till the
142 * balance goes to zero) or there are no splits left. */
143 while (1)
144 {
145 Split *subsplit;
146
147 subsplit = xaccSplitAssignToLot (split, lot);
148 if (subsplit == split)
149 {
150 PERR ("Accounting Policy gave us a split that "
151 "doesn't fit into this lot\n"
152 "lot baln=%s, isclosed=%d, aplit amt=%s",
154 gnc_lot_is_closed (lot),
155 gnc_num_dbg_to_string (split->amount));
156 break;
157 }
158
159 if (gnc_lot_is_closed (lot)) break;
160
161 split = pcy->PolicyGetSplit (pcy, lot);
162 if (!split) break;
163 }
165 LEAVE ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), xaccAccountGetName(acc));
166}
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
Definition Account.cpp:2100
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot,...
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
Definition gnc-lot.cpp:487
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
Definition gnc-lot.cpp:367
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.

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

172{
173 gnc_commodity *currency = nullptr;
174 SplitList *snode;
175 GList *node;
176 gnc_numeric zero = gnc_numeric_zero();
177 gnc_numeric value = zero;
178
179 if (!lot) return;
180
181 ENTER ("lot=%s", gnc_lot_get_title(lot));
182
183 for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
184 {
185 Split *s = GNC_SPLIT(snode->data);
186 xaccSplitComputeCapGains (s, nullptr);
187 }
188
189 /* We double-check only closed lots */
190 if (FALSE == gnc_lot_is_closed (lot))
191 {
192 LEAVE ("lot=%s is closed", gnc_lot_get_title(lot));
193 return;
194 }
195
196 for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
197 {
198 Split *s = GNC_SPLIT(snode->data);
199 Transaction *trans = s->parent;
200
201 /* Check to make sure all splits in the lot have a common currency */
202 if (nullptr == currency)
203 {
204 currency = trans->common_currency;
205 }
206 if (FALSE == gnc_commodity_equiv (currency, trans->common_currency))
207 {
208 /* This lot has mixed currencies. Can't double-balance.
209 * Silently punt */
210 PWARN ("Lot with multiple currencies:\n"
211 "\ttrans=%s curr=%s", xaccTransGetDescription(trans),
212 gnc_commodity_get_fullname(trans->common_currency));
213 break;
214 }
215
216 /* Now, total up the values */
217 value = gnc_numeric_add (value, xaccSplitGetValue (s),
218 GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
219 PINFO ("Split=%p value=%s Accum Lot value=%s", s,
220 gnc_num_dbg_to_string (s->value),
221 gnc_num_dbg_to_string (value));
222
223 }
224
225 if (FALSE == gnc_numeric_equal (value, zero))
226 {
227 /* Unhandled error condition. Not sure what to do here,
228 * Since the ComputeCapGains should have gotten it right.
229 * I suppose there might be small rounding errors, a penny or two,
230 * the ideal thing would to figure out why there's a rounding
231 * error, and fix that.
232 */
233 PERR ("Closed lot fails to double-balance !! lot value=%s",
234 gnc_num_dbg_to_string (value));
235 for (node = gnc_lot_get_split_list(lot); node; node = node->next)
236 {
237 Split *s = GNC_SPLIT(node->data);
238 PERR ("s=%p amt=%s val=%s", s,
239 gnc_num_dbg_to_string(s->amount),
240 gnc_num_dbg_to_string(s->value));
241 }
242 }
243
244 LEAVE ("lot=%s", gnc_lot_get_title(lot));
245}
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Retrieve the full name for the specified commodity.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Returns a list of all the splits in this lot.
Definition gnc-lot.cpp:425
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.

◆ 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);
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 {
121rethin:
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 gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
void xaccLotFill(GNCLot *lot)
The xaccLotFill() routine attempts to assign splits to the indicated lot until the lot balance goes t...
Definition Scrub2.cpp:95
void xaccLotScrubDoubleBalance(GNCLot *lot)
The xaccLotScrubDoubleBalance() routine examines the indicated lot.
Definition Scrub2.cpp:171

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

391{
392 gboolean rc = FALSE;
393 SplitList *node;
394
395 if (!lot) return FALSE;
396
397 ENTER (" ");
398restart:
399 for (node = gnc_lot_get_split_list(lot); node; node = node->next)
400 {
401 Split *s = GNC_SPLIT(node->data);
402 if (!xaccScrubMergeSubSplits(s, strict)) continue;
403
404 rc = TRUE;
405 goto restart;
406 }
407 LEAVE (" splits merged=%d", rc);
408 return rc;
409}
gboolean xaccScrubMergeSubSplits(Split *split, gboolean strict)
The xaccScrubMergeSubSplits() routine will merge together all of the splits that were at one time spl...
Definition Scrub2.cpp:329

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

330{
331 gboolean rc = FALSE;
332 Transaction *txn;
333 SplitList *node;
334 GNCLot *lot;
335
336 if (strict && (FALSE == is_subsplit (split))) return FALSE;
337
338 txn = split->parent;
339
340 // Don't mess with splits from an invoice transaction
341 // Those are the responsibility of the business code
342 if (gncInvoiceGetInvoiceFromTxn (txn)) return FALSE;
343
344 lot = xaccSplitGetLot (split);
345
346 ENTER ("(Lot=%s)", gnc_lot_get_title(lot));
347restart:
348 for (node = txn->splits; node; node = node->next)
349 {
350 Split *s = GNC_SPLIT(node->data);
351 if (xaccSplitGetLot (s) != lot) continue;
352 if (s == split) continue;
353 if (qof_instance_get_destroying(s)) continue;
354
355 // Don't mess with splits from an invoice transaction
356 // Those are the responsibility of the business code
357 if (gncInvoiceGetInvoiceFromTxn (s->parent)) return FALSE;
358
359 if (strict)
360 {
361 /* OK, this split is in the same lot (and thus same account)
362 * as the indicated split. Make sure it is really a subsplit
363 * of the split we started with. It's possible to have two
364 * splits in the same lot and transaction that are not subsplits
365 * of each other, the test-period test suite does this, for
366 * example. Only worry about adjacent sub-splits. By
367 * repeatedly merging adjacent subsplits, we'll get the non-
368 * adjacent ones too. */
369 if (!xaccSplitIsPeerSplit (split, s))
370 continue;
371 }
372
373 merge_splits (split, s);
374 rc = TRUE;
375 goto restart;
376 }
377 if (rc && gnc_numeric_zero_p (split->amount))
378 {
379 time64 pdate = xaccTransGetDate (txn);
380 gchar *pdatestr = gnc_ctime (&pdate);
381 PWARN ("Result of merge has zero amt!");
382 PWARN ("Transaction details - posted date %s - description %s", pdatestr, xaccTransGetDescription(txn));
383 g_free (pdatestr);
384 }
385 LEAVE (" splits merged=%d", rc);
386 return rc;
387}
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
gboolean xaccSplitIsPeerSplit(const Split *split, const Split *other_split)
Report if a split is a peer of this one.
Definition Split.cpp:2108

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

425{
426 split_scrub_or_dry_run (split, false);
427}

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

1122{
1123 SplitList *node;
1124 gnc_commodity *currency;
1125
1126 if (!trans) return;
1127
1128 /* If there are any orphaned splits in a transaction, then the
1129 * this routine will fail. Therefore, we want to make sure that
1130 * there are no orphans (splits without parent account).
1131 */
1132 xaccTransScrubOrphans (trans);
1133
1134 currency = xaccTransGetCurrency (trans);
1135 if (currency && gnc_commodity_is_currency(currency)) return;
1136
1137 currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans));
1138 if (currency)
1139 {
1140 xaccTransBeginEdit (trans);
1141 xaccTransSetCurrency (trans, currency);
1142 xaccTransCommitEdit (trans);
1143 }
1144 else
1145 {
1146 if (nullptr == trans->splits)
1147 {
1148 PWARN ("Transaction \"%s\" has no splits in it!", trans->description);
1149 }
1150 else
1151 {
1152 SplitList *node;
1153 char guid_str[GUID_ENCODING_LENGTH + 1];
1154 guid_to_string_buff(xaccTransGetGUID(trans), guid_str);
1155 PWARN ("no common transaction currency found for trans=\"%s\" (%s);",
1156 trans->description, guid_str);
1157
1158 for (node = trans->splits; node; node = node->next)
1159 {
1160 Split *split = GNC_SPLIT(node->data);
1161 if (nullptr == split->acc)
1162 {
1163 PWARN (" split=\"%s\" is not in any account!", split->memo);
1164 }
1165 else
1166 {
1167 gnc_commodity *currency = xaccAccountGetCommodity(split->acc);
1168 PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"",
1169 split->memo, xaccAccountGetName(split->acc),
1170 gnc_commodity_get_mnemonic(currency));
1171
1172 xaccTransBeginEdit (trans);
1173 xaccTransSetCurrency (trans, currency);
1174 xaccTransCommitEdit (trans);
1175 return;
1176 }
1177 }
1178 }
1179 return;
1180 }
1181
1182 for (node = trans->splits; node; node = node->next)
1183 {
1184 Split *sp = GNC_SPLIT(node->data);
1185
1187 xaccSplitGetValue (sp)))
1188 {
1189 gnc_commodity *acc_currency;
1190
1191 acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : nullptr;
1192 if (acc_currency == currency)
1193 {
1194 /* This Split needs fixing: The transaction-currency equals
1195 * the account-currency/commodity, but the amount/values are
1196 * inequal i.e. they still correspond to the security
1197 * (amount) and the currency (value). In the new model, the
1198 * value is the amount in the account-commodity -- so it
1199 * needs to be set to equal the amount (since the
1200 * account-currency doesn't exist anymore).
1201 *
1202 * Note: Nevertheless we lose some information here. Namely,
1203 * the information that the 'amount' in 'account-old-security'
1204 * was worth 'value' in 'account-old-currency'. Maybe it would
1205 * be better to store that information in the price database?
1206 * But then, for old currency transactions there is still the
1207 * 'other' transaction, which is going to keep that
1208 * information. So I don't bother with that here. -- cstim,
1209 * 2002/11/20. */
1210
1211 PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
1212 " old amount %s %s, new amount %s",
1213 trans->description, sp->memo,
1215 gnc_commodity_get_mnemonic (currency),
1217 xaccTransBeginEdit (trans);
1219 xaccTransCommitEdit (trans);
1220 }
1221 /*else
1222 {
1223 PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
1224 xaccSplitGetMemo (sp),
1225 gnc_num_dbg_to_string (amount),
1226 gnc_commodity_get_mnemonic (currency),
1227 gnc_num_dbg_to_string (value),
1228 gnc_commodity_get_mnemonic (acc_currency));
1229 }*/
1230 }
1231 }
1232
1233}
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
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.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
#define xaccTransGetGUID(X)
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
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:208
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
void xaccTransScrubOrphans(Transaction *trans)
The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.
Definition Scrub.cpp:179
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...

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

847{
848 gnc_numeric imbalance;
849
850 if (!trans) return;
851
852 ENTER ("()");
853
854 /* Must look for orphan splits even if there is no imbalance. */
855 xaccTransScrubSplits (trans);
856
857 /* Return immediately if things are balanced. */
858 if (xaccTransIsBalanced (trans))
859 {
860 LEAVE ("transaction is balanced");
861 return;
862 }
863
864 if (! xaccTransUseTradingAccounts (trans))
865 {
866 gnc_transaction_balance_no_trading (trans, root, account);
867 LEAVE ("transaction balanced, no managed trading accounts");
868 return;
869 }
870
871 xaccTransClearTradingSplits (trans);
872 imbalance = xaccTransGetImbalanceValue (trans);
873 if (! gnc_numeric_zero_p (imbalance))
874 {
875 PINFO ("Value unbalanced transaction");
876
877 add_balance_split (trans, imbalance, root, account);
878 }
879
880 gnc_transaction_balance_trading (trans, root);
882 {
883 LEAVE ("()");
884 return;
885 }
886 /* If the transaction is still not balanced, it's probably because there
887 are splits with zero amount and non-zero value. These are usually
888 realized gain/loss splits. Add a reversing split for each of them to
889 balance the value. */
890
891 gnc_transaction_balance_trading_more_splits (trans, root);
893 PERR("Balancing currencies unbalanced value");
894
895}
gboolean xaccTransIsBalanced(const Transaction *trans)
Returns true if the transaction is balanced according to the rules currently in effect.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
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:395

◆ xaccTransScrubOrphans()

void xaccTransScrubOrphans ( Transaction *  trans)

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

Definition at line 179 of file Scrub.cpp.

180{
181 SplitList *node;
182 QofBook *book = nullptr;
183 Account *root = nullptr;
184
185 if (!trans) return;
186
187 for (node = trans->splits; node; node = node->next)
188 {
189 Split *split = GNC_SPLIT(node->data);
190 if (abort_now) break;
191
192 if (split->acc)
193 {
194 TransScrubOrphansFast (trans, gnc_account_get_root(split->acc));
195 return;
196 }
197 }
198
199 /* If we got to here, then *none* of the splits belonged to an
200 * account. Not a happy situation. We should dig an account
201 * out of the book the transaction belongs to.
202 * XXX we should probably *always* to this, instead of the above loop!
203 */
204 PINFO ("Free Floating Transaction!");
205 book = xaccTransGetBook (trans);
206 root = gnc_book_get_root_account (book);
207 TransScrubOrphansFast (trans, root);
208}
Account * gnc_account_get_root(Account *acc)
This routine returns the root account of the account tree that the specified account belongs to.
Definition Account.cpp:2942
#define xaccTransGetBook(X)
QofBook reference.
Definition qofbook-p.hpp:47

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

1544{
1545 time64 orig = xaccTransGetDate(trans);
1546 if(orig == INT64_MAX)
1547 {
1548 GDate date = xaccTransGetDatePostedGDate(trans);
1549 time64 time = gdate_to_time64(date);
1550 if(time != INT64_MAX)
1551 {
1552 // xaccTransSetDatePostedSecs handles committing the change.
1553 xaccTransSetDatePostedSecs(trans, time);
1554 }
1555 }
1556}
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Retrieve the posted date of the transaction.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction,...

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

396{
397 if (!trans) return;
398
399 gnc_commodity *currency = xaccTransGetCurrency (trans);
400 if (!currency)
401 PERR ("Transaction doesn't have a currency!");
402
403 bool must_scrub = false;
404
405 for (GList *n = xaccTransGetSplitList (trans); !must_scrub && n; n = g_list_next (n))
406 if (split_scrub_or_dry_run (GNC_SPLIT(n->data), true))
407 must_scrub = true;
408
409 if (!must_scrub)
410 return;
411
412 xaccTransBeginEdit(trans);
413 /* The split scrub expects the transaction to have a currency! */
414
415 for (GList *n = xaccTransGetSplitList (trans); n; n = g_list_next (n))
416 xaccSplitScrub (GNC_SPLIT(n->data));
417
418 xaccTransCommitEdit(trans);
419}
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.