Bug 754209 - Bills can be posted multiple times from "find bill" search results - follow up

This commit adds code to check & repair that removes the read only status of the bogus transactions so the user can go in the AP/AR account and delete these bad transactions.

Translators: this commit introduces a new translatable string.
This commit is contained in:
Geert Janssens 2016-03-19 13:44:10 +01:00
parent d45886f73b
commit 0f66e20005
4 changed files with 142 additions and 14 deletions

View File

@ -462,6 +462,50 @@ gncScrubBusinessLot (GNCLot *lot)
return splits_deleted;
}
void
gncScrubBusinessSplit (Split *split)
{
const gchar *memo = _("Please delete this transaction. Explanation at http://wiki.gnucash.org/wiki/Business_Features_Issues#Double_Posting");
Transaction *txn;
if (!split) return;
ENTER ("(split=%p)", split);
txn = xaccSplitGetParent (split);
if (txn)
{
gchar txntype = xaccTransGetTxnType (txn);
const gchar *read_only = xaccTransGetReadOnly (txn);
gboolean is_void = xaccTransGetVoidStatus (txn);
GNCLot *lot = xaccSplitGetLot (split);
/* Look for transactions as a result of double posting an invoice or bill
* Refer to https://bugzilla.gnome.org/show_bug.cgi?id=754209
* to learn how this could have happened in the past.
* Characteristics of such transaction are:
* - read only
* - not voided (to ensure read only is set by the business functions)
* - transaction type is none (should be type invoice for proper post transactions)
* - assigned to a lot
*/
if ((txntype == TXN_TYPE_NONE) && read_only && !is_void && lot)
{
gchar *txn_date = qof_print_date (xaccTransGetDateEntered (txn));
xaccTransClearReadOnly (txn);
xaccSplitSetMemo (split, memo);
gnc_lot_remove_split (lot, split);
PWARN("Cleared double post status of transaction \"%s\", dated %s. "
"Please delete transaction and verify balance.",
xaccTransGetDescription (txn),
txn_date);
g_free (txn_date);
}
}
LEAVE ("(split=%p)", split);
}
/* ============================================================== */
void
@ -505,20 +549,72 @@ gncScrubBusinessAccountLots (Account *acc)
/* ============================================================== */
void
gncScrubBusinessAccountSplits (Account *acc)
{
SplitList *splits, *node;
gint split_count = 0;
gint curr_split_no = 1;
const gchar *str;
if (!acc) return;
if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
str = xaccAccountGetName(acc);
str = str ? str : "(null)";
ENTER ("(acc=%s)", str);
PINFO ("Cleaning up superfluous lot links in account %s \n", str);
xaccAccountBeginEdit(acc);
splits = xaccAccountGetSplitList(acc);
split_count = g_list_length (splits);
for (node = splits; node; node = node->next)
{
Split *split = node->data;
PINFO("Start processing split %d of %d",
curr_split_no, split_count);
if (split)
gncScrubBusinessSplit (split);
PINFO("Finished processing split %d of %d",
curr_split_no, split_count);
curr_split_no++;
}
xaccAccountCommitEdit(acc);
LEAVE ("(acc=%s)", str);
}
/* ============================================================== */
void
gncScrubBusinessAccount (Account *acc)
{
if (!acc) return;
if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
gncScrubBusinessAccountLots (acc);
gncScrubBusinessAccountSplits (acc);
}
/* ============================================================== */
static void
lot_scrub_cb (Account *acc, gpointer data)
{
if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
gncScrubBusinessAccountLots (acc);
gncScrubBusinessAccount (acc);
}
void
gncScrubBusinessAccountTreeLots (Account *acc)
gncScrubBusinessAccountTree (Account *acc)
{
if (!acc) return;
gnc_account_foreach_descendant(acc, lot_scrub_cb, NULL);
gncScrubBusinessAccountLots (acc);
gncScrubBusinessAccount (acc);
}
/* ========================== END OF FILE ========================= */

View File

@ -54,6 +54,21 @@
*/
gboolean gncScrubBusinessLot (GNCLot *lot);
/** The gncScrubBusinessSplit() function will fix all issues found with
* the given split.
*
* Currently this function only does one thing: 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.
*/
void gncScrubBusinessSplit (Split *split);
/** The gncScrubBusinessAccountLots() function will call
* gncScrubBusinessLot() on each lot in the given account.
*
@ -63,15 +78,26 @@ gboolean gncScrubBusinessLot (GNCLot *lot);
*/
void gncScrubBusinessAccountLots (Account *acc);
/** The gncScrubBusinessAccountTreeLots() function will call
* gncScrubBusinessAccountLots() on each lot in the given account
* and its sub accounts.
*
* This routine is the primary routine for ensuring that the
* lot structure of every lot of a business account is in good
* order.
/** The gncScrubBusinessAccountSplits() function will call
* gncScrubBusinessSplit() on each split in the given account.
*/
void gncScrubBusinessAccountTreeLots (Account *acc);
void gncScrubBusinessAccountSplits (Account *acc);
/** 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.
*/
void gncScrubBusinessAccount (Account *acc);
/** The gncScrubBusinessAccountTreeLots() function will call
* gncScrubBusinessAccount() on the given account
* and its sub accounts.
*/
void gncScrubBusinessAccountTree (Account *acc);
/** @} */
#endif /* GNC_SCRUBBUSINESS_H */

View File

@ -1573,7 +1573,7 @@ gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountT
if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
xaccAccountScrubLots(account);
gncScrubBusinessAccountLots(account);
gncScrubBusinessAccount(account);
gnc_resume_gui_refresh ();
@ -1595,7 +1595,7 @@ gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAcco
if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
xaccAccountTreeScrubLots(account);
gncScrubBusinessAccountTreeLots(account);
gncScrubBusinessAccountTree(account);
gnc_resume_gui_refresh ();
}
@ -1613,7 +1613,7 @@ gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAcco
if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
xaccAccountTreeScrubLots(root);
gncScrubBusinessAccountTreeLots(root);
gncScrubBusinessAccountTree(root);
gnc_resume_gui_refresh ();
}

View File

@ -3726,7 +3726,10 @@ gnc_plugin_page_register_cmd_scrub_current (GtkAction *action,
split = gnc_split_register_get_current_split (reg);
lot = xaccSplitGetLot (split);
if (lot && xaccAccountIsAPARType (xaccAccountGetType (xaccSplitGetAccount (split))))
{
gncScrubBusinessLot (lot);
gncScrubBusinessSplit (split);
}
gnc_resume_gui_refresh();
LEAVE(" ");
}
@ -3773,7 +3776,10 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction *action,
lot = xaccSplitGetLot (split);
if (lot && xaccAccountIsAPARType (xaccAccountGetType (xaccSplitGetAccount (split))))
{
gncScrubBusinessLot (lot);
gncScrubBusinessSplit (split);
}
PINFO("Finished processing split %d of %d",
curr_split_no, split_count);