mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Paul Campbell's code to allow child accounts to be reconciled
with the parent. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@5412 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
a85fb2a89b
commit
277796dfad
1
AUTHORS
1
AUTHORS
@ -84,6 +84,7 @@ Terry Boldt <tboldt@attglobal.net> financial calculator and expression parser
|
||||
Richard Braakman <dark@xs4all.nl) xml version configure patch
|
||||
Simon Britnell <simon.britnell@peace.com> patch to RPM spec
|
||||
Christopher B. Browne <cbbrowne@hex.net> for perl, lots of scheme and documentation updates
|
||||
Paul Campbell <kemitix@users.sourceforge.net> reconcile children patch
|
||||
Conrad Canterford <conrad@mail.watersprite.com.au> register bug fix
|
||||
Bill Carlson <wwc@wwcnet.nu> performance improvements
|
||||
David Mar?n Carre?o <davefx@aspl.f2s.com> Spanish translation of account setup.
|
||||
|
@ -267,6 +267,14 @@ linkend="scheme"> Scheme </link>, the <link linkend="gwrap"> g-wrap
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm><email>kemitix@users.sourceforge.net</email> Paul
|
||||
Campbell</glossterm>
|
||||
<glossdef>
|
||||
<para>reconcile children patch</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm><email>conrad@mail.watersprite.com.au</email> Conrad
|
||||
Canterford</glossterm>
|
||||
|
@ -311,6 +311,54 @@ gnc_account_get_balance_in_currency (Account *account,
|
||||
}
|
||||
|
||||
|
||||
gnc_numeric
|
||||
gnc_ui_convert_balance_to_currency(gnc_numeric balance, gnc_commodity *balance_currency, gnc_commodity *currency)
|
||||
{
|
||||
GNCBook *book;
|
||||
GNCPriceDB *pdb;
|
||||
GNCPrice *price;
|
||||
|
||||
if (gnc_numeric_zero_p (balance) ||
|
||||
gnc_commodity_equiv (currency, balance_currency))
|
||||
return balance;
|
||||
|
||||
book = gnc_get_current_book ();
|
||||
pdb = gnc_book_get_pricedb (book);
|
||||
|
||||
price = gnc_pricedb_lookup_latest (pdb, balance_currency, currency);
|
||||
if (!price)
|
||||
return gnc_numeric_zero ();
|
||||
|
||||
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
|
||||
gnc_commodity_get_fraction (currency),
|
||||
GNC_RND_ROUND);
|
||||
|
||||
gnc_price_unref (price);
|
||||
|
||||
return balance;
|
||||
}
|
||||
|
||||
static gnc_numeric
|
||||
gnc_account_get_reconciled_balance_in_currency (Account *account,
|
||||
gnc_commodity *currency)
|
||||
{
|
||||
GNCBook *book;
|
||||
GNCPriceDB *pdb;
|
||||
GNCPrice *price;
|
||||
gboolean has_shares;
|
||||
gnc_numeric balance;
|
||||
GNCAccountType atype;
|
||||
gnc_commodity *balance_currency;
|
||||
|
||||
if (!account || !currency)
|
||||
return gnc_numeric_zero ();
|
||||
|
||||
balance = xaccAccountGetReconciledBalance (account);
|
||||
balance_currency = DxaccAccountGetCurrency (account);
|
||||
|
||||
return gnc_ui_convert_balance_to_currency (balance, balance_currency, currency);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gnc_commodity *currency;
|
||||
@ -336,6 +384,21 @@ balance_helper (Account *account, gpointer data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
reconciled_balance_helper (Account *account, gpointer data)
|
||||
{
|
||||
CurrencyBalance *cb = data;
|
||||
gnc_numeric balance;
|
||||
|
||||
balance = gnc_account_get_reconciled_balance_in_currency (account, cb->currency);
|
||||
|
||||
cb->balance = gnc_numeric_add (cb->balance, balance,
|
||||
gnc_commodity_get_fraction (cb->currency),
|
||||
GNC_RND_ROUND);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gnc_numeric
|
||||
gnc_ui_account_get_balance (Account *account, gboolean include_children)
|
||||
{
|
||||
@ -450,6 +513,82 @@ gnc_ui_account_get_tax_info_string (Account *account)
|
||||
}
|
||||
|
||||
|
||||
gnc_numeric
|
||||
gnc_ui_account_get_reconciled_balance (Account *account,
|
||||
gboolean include_children)
|
||||
{
|
||||
gnc_numeric balance;
|
||||
gnc_commodity *currency;
|
||||
|
||||
if (account == NULL)
|
||||
return gnc_numeric_zero ();
|
||||
|
||||
currency = DxaccAccountGetCurrency (account);
|
||||
|
||||
balance = gnc_account_get_reconciled_balance_in_currency (account, currency);
|
||||
|
||||
if (include_children)
|
||||
{
|
||||
AccountGroup *children;
|
||||
CurrencyBalance cb = { currency, balance };
|
||||
|
||||
children = xaccAccountGetChildren (account);
|
||||
|
||||
xaccGroupForEachAccount (children, reconciled_balance_helper, &cb, TRUE);
|
||||
|
||||
balance = cb.balance;
|
||||
}
|
||||
|
||||
/* reverse sign if needed */
|
||||
if (gnc_reverse_balance (account))
|
||||
balance = gnc_numeric_neg (balance);
|
||||
|
||||
return balance;
|
||||
}
|
||||
|
||||
gnc_numeric
|
||||
gnc_ui_account_get_balance_as_of_date (Account *account, time_t date,
|
||||
gboolean include_children)
|
||||
{
|
||||
gnc_numeric balance;
|
||||
gnc_commodity *currency;
|
||||
|
||||
if (account == NULL)
|
||||
return gnc_numeric_zero ();
|
||||
|
||||
currency = DxaccAccountGetCurrency (account);
|
||||
balance = xaccAccountGetBalanceAsOfDate (account, date);
|
||||
|
||||
if (include_children)
|
||||
{
|
||||
AccountGroup *children_group;
|
||||
GList *children, *node;
|
||||
|
||||
children_group = xaccAccountGetChildren (account);
|
||||
children = xaccGroupGetSubAccounts (children_group);
|
||||
|
||||
for( node = children; node; node = node->next )
|
||||
{
|
||||
Account *child;
|
||||
gnc_commodity *child_currency;
|
||||
gnc_numeric child_balance;
|
||||
|
||||
child = (Account *)node->data;
|
||||
child_currency = DxaccAccountGetCurrency (child);
|
||||
child_balance = xaccAccountGetBalanceAsOfDate (child, date);
|
||||
child_balance = gnc_ui_convert_balance_to_currency
|
||||
(child_balance, child_currency, currency);
|
||||
balance = gnc_numeric_add_fixed (balance, child_balance);
|
||||
}
|
||||
}
|
||||
|
||||
/* reverse sign if needed */
|
||||
if (gnc_reverse_balance (account))
|
||||
balance = gnc_numeric_neg (balance);
|
||||
|
||||
return balance;
|
||||
}
|
||||
|
||||
char *
|
||||
gnc_ui_account_get_field_value_string (Account *account,
|
||||
AccountFieldCode field)
|
||||
|
@ -73,9 +73,16 @@ const char * gnc_ui_account_get_field_name (AccountFieldCode field);
|
||||
char * gnc_ui_account_get_field_value_string (Account *account,
|
||||
AccountFieldCode field);
|
||||
|
||||
gnc_numeric gnc_ui_convert_balance_to_currency(gnc_numeric balance,
|
||||
gnc_commodity *balance_currency,
|
||||
gnc_commodity *currency);
|
||||
|
||||
gnc_numeric gnc_ui_account_get_balance (Account *account,
|
||||
gboolean include_children);
|
||||
|
||||
gnc_numeric gnc_ui_account_get_reconciled_balance(Account *account, gboolean include_children);
|
||||
gnc_numeric gnc_ui_account_get_balance_as_of_date (Account *account, time_t date, gboolean include_children);
|
||||
|
||||
const char * gnc_get_reconcile_str (char reconciled_flag);
|
||||
|
||||
typedef enum
|
||||
|
@ -2054,6 +2054,48 @@ xaccAccountGetQuoteTZ(Account *acc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
void
|
||||
xaccAccountSetReconcileChildrenStatus(Account *account, gboolean status)
|
||||
{
|
||||
kvp_frame *frame;
|
||||
if (!account)
|
||||
return;
|
||||
|
||||
xaccAccountBeginEdit (account);
|
||||
|
||||
frame = kvp_frame_get_frame (account->kvp_data, "reconcile-info", NULL);
|
||||
kvp_frame_set_slot_nc (frame,
|
||||
"include-children",
|
||||
status ? kvp_value_new_gint64 (status) : NULL);
|
||||
account->core_dirty = TRUE;
|
||||
xaccAccountCommitEdit (account);
|
||||
return;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
gboolean
|
||||
xaccAccountGetReconcileChildrenStatus(Account *account)
|
||||
{
|
||||
kvp_value *status;
|
||||
if (!account)
|
||||
return FALSE;
|
||||
/* access the account's kvp-data for status and return that, if no value
|
||||
* is found then we can assume not to include the children, that being
|
||||
* the default behaviour
|
||||
*/
|
||||
status = kvp_frame_get_slot_path (account->kvp_data,
|
||||
"reconcile-info",
|
||||
"include-children",
|
||||
NULL);
|
||||
if (!status)
|
||||
return FALSE;
|
||||
return kvp_value_get_gint64 (status);
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
|
@ -234,6 +234,9 @@ gnc_numeric xaccAccountGetBalance (Account *account);
|
||||
gnc_numeric xaccAccountGetClearedBalance (Account *account);
|
||||
gnc_numeric xaccAccountGetReconciledBalance (Account *account);
|
||||
|
||||
void xaccAccountSetReconcileChildrenStatus(Account *account, gboolean status);
|
||||
gboolean xaccAccountGetReconcileChildrenStatus(Account *account);
|
||||
|
||||
gnc_numeric xaccAccountGetBalanceAsOfDate (Account *account, time_t date);
|
||||
|
||||
GList* xaccAccountGetSplitList (Account *account);
|
||||
|
@ -102,6 +102,12 @@ Type: frame
|
||||
Entities: Account
|
||||
Use: store reconcile information about accounts
|
||||
|
||||
Name: reconcile-info/include-children
|
||||
Type: gint64
|
||||
Entities: Account
|
||||
Use: A boolean flag indicating whether transactions in sub-accounts should be
|
||||
included during reconcilition.
|
||||
|
||||
Name: reconcile-info/last-date
|
||||
Type: frame
|
||||
Entities: Account
|
||||
|
@ -98,6 +98,7 @@ GtkWidget *
|
||||
gnc_reconcile_list_new(Account *account, GNCReconcileListType type)
|
||||
{
|
||||
GNCReconcileList *list;
|
||||
gboolean include_children;
|
||||
|
||||
g_assert(account != NULL);
|
||||
g_assert((type == RECLIST_DEBIT) || (type == RECLIST_CREDIT));
|
||||
@ -114,6 +115,20 @@ gnc_reconcile_list_new(Account *account, GNCReconcileListType type)
|
||||
/* match the account */
|
||||
xaccQueryAddSingleAccountMatch(list->query, account, QUERY_OR);
|
||||
|
||||
include_children = xaccAccountGetReconcileChildrenStatus(account);
|
||||
if(include_children)
|
||||
{
|
||||
/* match child accounts */
|
||||
AccountGroup *account_group = xaccAccountGetChildren(account);
|
||||
GList *children_list = xaccGroupGetSubAccounts(account_group);
|
||||
GList *node;
|
||||
|
||||
for (node = children_list; node; node = node->next)
|
||||
xaccQueryAddSingleAccountMatch (list->query, node->data, QUERY_OR);
|
||||
|
||||
g_list_free (children_list);
|
||||
}
|
||||
|
||||
if (type == RECLIST_CREDIT)
|
||||
DxaccQueryAddAmountMatch(list->query, 0.0, AMT_SGN_MATCH_CREDIT,
|
||||
AMT_MATCH_ATLEAST, QUERY_AND);
|
||||
@ -241,11 +256,87 @@ gnc_reconcile_list_class_init (GNCReconcileListClass *klass)
|
||||
klass->double_click_split = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_reconcile_list_toggle_row(GNCReconcileList *list, gint row)
|
||||
{
|
||||
Split *split, *current;
|
||||
|
||||
g_assert (IS_GNC_RECONCILE_LIST(list));
|
||||
g_assert (list->reconciled != NULL);
|
||||
|
||||
if (list->no_toggle)
|
||||
return;
|
||||
|
||||
split = gtk_clist_get_row_data (GTK_CLIST(list), row);
|
||||
current = g_hash_table_lookup (list->reconciled, split);
|
||||
|
||||
list->current_split = split;
|
||||
|
||||
if (current == NULL)
|
||||
g_hash_table_insert (list->reconciled, split, split);
|
||||
else
|
||||
g_hash_table_remove (list->reconciled, split);
|
||||
|
||||
update_toggle (GTK_CLIST (list), row);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_reconcile_list_toggle_children(Account *account, GNCReconcileList *list, Split *split)
|
||||
{
|
||||
AccountGroup *account_group;
|
||||
GList *child_accounts, *node;
|
||||
Transaction *transaction;
|
||||
|
||||
/*
|
||||
* Need to get all splits in this transaction and identify any that are
|
||||
* in the same heirarchy as the account being reconciled (not necessarily
|
||||
* the account this split is from.)
|
||||
*
|
||||
* For each of these splits toggle them all to the same state.
|
||||
*/
|
||||
account_group = xaccAccountGetChildren(account);
|
||||
child_accounts = xaccGroupGetSubAccounts(account_group);
|
||||
child_accounts = g_list_prepend(child_accounts, account);
|
||||
transaction = xaccSplitGetParent(split);
|
||||
for(node = xaccTransGetSplitList(transaction); node; node = node->next)
|
||||
{
|
||||
Split *other_split;
|
||||
Account *other_account;
|
||||
GNCReconcileList *current_list;
|
||||
gint row;
|
||||
GtkCList *split_list;
|
||||
|
||||
other_split = node->data;
|
||||
other_account = xaccSplitGetAccount(other_split);
|
||||
if(other_split == split)
|
||||
continue;
|
||||
/* Check this 'other' account in in the same heirarchy */
|
||||
if(!g_list_find(child_accounts,other_account))
|
||||
continue;
|
||||
/* Search our sibling list for this split first. We search the
|
||||
* sibling list first because that it where it is most likely to be.
|
||||
*/
|
||||
current_list = list->sibling;
|
||||
row = gtk_clist_find_row_from_data(GTK_CLIST(¤t_list->clist), other_split);
|
||||
if(row == -1) {
|
||||
/* Not in the sibling list, try this list */
|
||||
current_list = list;
|
||||
row = gtk_clist_find_row_from_data(GTK_CLIST(¤t_list->clist), other_split);
|
||||
if(row == -1)
|
||||
/* We can't find it, nothing more I can do about it */
|
||||
continue;
|
||||
}
|
||||
gnc_reconcile_list_toggle_row(current_list, row);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_reconcile_list_toggle (GNCReconcileList *list)
|
||||
{
|
||||
Split *split, *current;
|
||||
gint row;
|
||||
Account * account;
|
||||
gboolean include_children;
|
||||
|
||||
g_assert (IS_GNC_RECONCILE_LIST(list));
|
||||
g_assert (list->reconciled != NULL);
|
||||
@ -266,6 +357,10 @@ gnc_reconcile_list_toggle (GNCReconcileList *list)
|
||||
|
||||
update_toggle (GTK_CLIST (list), row);
|
||||
|
||||
include_children = xaccAccountGetReconcileChildrenStatus(list->account);
|
||||
if(include_children)
|
||||
gnc_reconcile_list_toggle_children(list->account, list, split);
|
||||
|
||||
gtk_signal_emit (GTK_OBJECT (list),
|
||||
reconcile_list_signals[TOGGLE_RECONCILED], split);
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ struct _GNCReconcileList
|
||||
|
||||
Account *account;
|
||||
Query *query;
|
||||
|
||||
GNCReconcileList *sibling;
|
||||
};
|
||||
|
||||
struct _GNCReconcileListClass
|
||||
|
@ -224,7 +224,7 @@ recnRecalculateBalance (RecnWindow *recnData)
|
||||
gnc_numeric reconciled;
|
||||
gnc_numeric diff;
|
||||
GNCPrintAmountInfo print_info;
|
||||
gboolean reverse_balance;
|
||||
gboolean reverse_balance, include_children;
|
||||
|
||||
account = recn_get_account (recnData);
|
||||
if (!account)
|
||||
@ -233,7 +233,8 @@ recnRecalculateBalance (RecnWindow *recnData)
|
||||
reverse_balance = gnc_reverse_balance(account);
|
||||
|
||||
/* update the starting balance */
|
||||
starting = xaccAccountGetReconciledBalance(account);
|
||||
include_children = xaccAccountGetReconcileChildrenStatus(account);
|
||||
starting = gnc_ui_account_get_reconciled_balance(account, include_children);
|
||||
print_info = gnc_account_print_info (account, TRUE);
|
||||
|
||||
if (reverse_balance)
|
||||
@ -553,13 +554,14 @@ static gboolean
|
||||
startRecnWindow(GtkWidget *parent, Account *account,
|
||||
gnc_numeric *new_ending, time_t *statement_date)
|
||||
{
|
||||
GtkWidget *dialog, *end_value, *date_value;
|
||||
GtkWidget *dialog, *end_value, *date_value, *include_children_button;
|
||||
startRecnWindowData data = { NULL };
|
||||
gboolean auto_interest_xfer_option;
|
||||
GNCPrintAmountInfo print_info;
|
||||
gnc_numeric ending;
|
||||
char *title;
|
||||
int result;
|
||||
gboolean include_children;
|
||||
|
||||
/* Initialize the data structure that will be used for several callbacks
|
||||
* throughout this file with the relevant info. Some initialization is
|
||||
@ -575,7 +577,10 @@ startRecnWindow(GtkWidget *parent, Account *account,
|
||||
auto_interest_xfer_option =
|
||||
gnc_recn_interest_xfer_get_auto_interest_xfer_allowed( account );
|
||||
|
||||
ending = xaccAccountGetReconciledBalance(account);
|
||||
include_children = xaccAccountGetReconcileChildrenStatus(account);
|
||||
|
||||
ending = gnc_ui_account_get_reconciled_balance(account,
|
||||
include_children);
|
||||
print_info = gnc_account_print_info (account, TRUE);
|
||||
|
||||
if (gnc_reverse_balance(account))
|
||||
@ -610,10 +615,16 @@ startRecnWindow(GtkWidget *parent, Account *account,
|
||||
GtkWidget *end_title = gtk_label_new(_("Ending Balance:"));
|
||||
GtkWidget *start_value =
|
||||
gtk_label_new(xaccPrintAmount (ending, print_info));
|
||||
GtkWidget *blank_label = gtk_label_new("");
|
||||
GtkWidget *vbox = GNOME_DIALOG(dialog)->vbox;
|
||||
GtkWidget *entry;
|
||||
GtkWidget *interest = NULL;
|
||||
|
||||
include_children_button =
|
||||
gtk_check_button_new_with_label(_("Include Subaccounts"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(include_children_button),
|
||||
include_children);
|
||||
|
||||
date_value = gnc_date_edit_new(*statement_date, FALSE, FALSE);
|
||||
|
||||
end_value = gnc_amount_edit_new ();
|
||||
@ -655,10 +666,12 @@ startRecnWindow(GtkWidget *parent, Account *account,
|
||||
gtk_box_pack_start(GTK_BOX(left_column), date_title, TRUE, TRUE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(left_column), start_title, TRUE, TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(left_column), end_title, TRUE, TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(left_column), blank_label, TRUE, TRUE, 0);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(right_column), date_value, TRUE, TRUE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(right_column), start_value, TRUE, TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(right_column), end_value, TRUE, TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(right_column), include_children_button, TRUE, TRUE, 0);
|
||||
|
||||
/* if it's possible to enter an interest payment or charge for this
|
||||
* account, add a button so that the user can pop up the appropriate
|
||||
@ -707,6 +720,9 @@ startRecnWindow(GtkWidget *parent, Account *account,
|
||||
|
||||
if (gnc_reverse_balance(account))
|
||||
*new_ending = gnc_numeric_neg (*new_ending);
|
||||
|
||||
xaccAccountSetReconcileChildrenStatus
|
||||
(account, GTK_TOGGLE_BUTTON(include_children_button)->active);
|
||||
}
|
||||
|
||||
/* cancel or delete */
|
||||
@ -1604,7 +1620,10 @@ gnc_get_reconcile_info (Account *account,
|
||||
/* if the account wasn't previously postponed, try to predict
|
||||
* the statement balance based on the statement date.
|
||||
*/
|
||||
*new_ending = xaccAccountGetBalanceAsOfDate(account, *statement_date);
|
||||
*new_ending =
|
||||
gnc_ui_account_get_balance_as_of_date
|
||||
(account, *statement_date,
|
||||
xaccAccountGetReconcileChildrenStatus(account));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1844,6 +1863,9 @@ recnWindow (GtkWidget *parent, Account *account)
|
||||
(account, RECLIST_CREDIT, recnData,
|
||||
&recnData->credit, &recnData->total_credit);
|
||||
|
||||
GNC_RECONCILE_LIST(recnData->debit)->sibling = GNC_RECONCILE_LIST(recnData->credit);
|
||||
GNC_RECONCILE_LIST(recnData->credit)->sibling = GNC_RECONCILE_LIST(recnData->debit);
|
||||
|
||||
popup = gnc_recn_create_popup_menu(recnData);
|
||||
gnome_popup_menu_attach(popup, recnData->debit, recnData);
|
||||
gnome_popup_menu_attach(popup, recnData->credit, recnData);
|
||||
|
Loading…
Reference in New Issue
Block a user