GnuCash c935c2f+
Loading...
Searching...
No Matches
dialog-book-close.c
1/********************************************************************\
2 * dialog-book-close.c -- dialog for helping the user close the *
3 * book at the end of the year by adding *
4 * zero-izing splits to all Income and *
5 * Expense accounts *
6 * *
7 * Copyright (C) 2007-8 Derek Atkins <derek@ihtfp.com> *
8 * *
9 * This program is free software; you can redistribute it and/or *
10 * modify it under the terms of the GNU General Public License as *
11 * published by the Free Software Foundation; either version 2 of *
12 * the License, or (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License*
20 * along with this program; if not, contact: *
21 * *
22 * Free Software Foundation Voice: +1-617-542-5942 *
23 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
24 * Boston, MA 02110-1301, USA gnu@gnu.org *
25\********************************************************************/
26
27#include <config.h>
28
29#include <gtk/gtk.h>
30#include <glib/gi18n.h>
31
32#include "dialog-utils.h"
33#include "gnc-engine.h"
34#include "Transaction.h"
35#include "Split.h"
36#include "Account.h"
37#include "gnc-ui.h"
38#include "gnc-gui-query.h"
39#include "dialog-book-close.h"
40#include "gnc-account-sel.h"
41#include "gnc-component-manager.h"
42#include "gnc-date-edit.h"
43#include "gnc-session.h"
44#include "gnc-ui-util.h"
45
46#define DIALOG_BOOK_CLOSE_CM_CLASS "dialog-book-close"
47
48void gnc_book_close_response_cb(GtkDialog *, gint, GtkDialog *);
49
50/* This static indicates the debugging module that this .o belongs to. */
51static QofLogModule log_module = GNC_MOD_GUI;
52
54{
55 /* Passed in by the creator */
56 QofBook* book;
57
58 /* Parts of the dialog */
59 GtkWidget* dialog;
60 GtkWidget* close_date_widget;
61 GtkWidget* income_acct_widget;
62 GtkWidget* expense_acct_widget;
63 GtkWidget* desc_widget;
64
65 /* The final settings */
66 time64 close_date;
67 const char* desc;
68
69 /* Component registration */
70 gint component_manager_id;
71};
72
74{
75 struct CloseBookWindow* cbw;
76 Account* base_acct;
77 GNCAccountType acct_type;
78 GHashTable* txns;
79 guint hash_size;
80};
81
83{
84 gnc_commodity* cmdty;
85 Transaction* txn;
86 gnc_numeric total;
87};
88
89static struct CACBTransactionList*
90find_or_create_txn(struct CloseAccountsCB* cacb, gnc_commodity* cmdty)
91{
92 struct CACBTransactionList* txn;
93
94 g_return_val_if_fail(cacb, NULL);
95 g_return_val_if_fail(cmdty, NULL);
96
97 txn = g_hash_table_lookup(cacb->txns, cmdty);
98 if (!txn)
99 {
100 txn = g_new0(struct CACBTransactionList, 1);
101 txn->cmdty = cmdty;
102 txn->total = gnc_numeric_zero();
103 txn->txn = xaccMallocTransaction(cacb->cbw->book);
104 xaccTransBeginEdit(txn->txn);
105 xaccTransSetDateEnteredSecs(txn->txn, gnc_time (NULL));
106 xaccTransSetDatePostedSecsNormalized(txn->txn, cacb->cbw->close_date);
107
108 xaccTransSetDescription(txn->txn, cacb->cbw->desc);
109 xaccTransSetCurrency(txn->txn, cmdty);
110 xaccTransSetIsClosingTxn(txn->txn, TRUE);
111 g_hash_table_insert(cacb->txns, cmdty, txn);
112 }
113
114 return txn;
115}
116
117/* Make sure that the account is of the correct type.
118 * then make sure the account has a balance as of the closing date.
119 * then get the account commodity and find the appropriate
120 * balancing transaction for that commodity and add this balance
121 * to it.
122 */
123static void close_accounts_cb(Account *a, gpointer data)
124{
125 struct CloseAccountsCB* cacb = data;
126 struct CACBTransactionList* txn;
127 gnc_commodity* acct_commodity;
128 Split* split;
129 gnc_numeric bal;
130
131 g_return_if_fail(a);
132 g_return_if_fail(cacb);
133 g_return_if_fail(cacb->cbw);
134 g_return_if_fail(cacb->txns);
135
136 if (cacb->acct_type != xaccAccountGetType(a))
137 return;
138
139 bal = xaccAccountGetBalanceAsOfDate(a, gnc_time64_get_day_end (cacb->cbw->close_date));
140 if (gnc_numeric_zero_p(bal))
141 return;
142
143 acct_commodity = gnc_account_or_default_currency(a, NULL);
144 g_assert(acct_commodity);
145
146 txn = find_or_create_txn(cacb, acct_commodity);
147 g_assert(txn);
148
149 split = xaccMallocSplit(cacb->cbw->book);
150 xaccSplitSetParent(split, txn->txn);
152 xaccAccountInsertSplit(a, split);
153 xaccSplitSetBaseValue(split, gnc_numeric_neg(bal), acct_commodity);
155 txn->total = gnc_numeric_add(txn->total, bal, GNC_DENOM_AUTO,
156 GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
157}
158
159
160static void finish_txn_cb(gnc_commodity* cmdty,
161 struct CACBTransactionList* txn,
162 struct CloseAccountsCB* cacb)
163{
164 Account* acc;
165 Split* split;
166
167 g_return_if_fail(cmdty);
168 g_return_if_fail(txn);
169 g_return_if_fail(cacb);
170 g_return_if_fail(cacb->hash_size);
171
172 /* If we only have one currency and the base account uses
173 * that currency, then we can use that account. Otherwise,
174 * create a subaccount for each currency.
175 */
176 if (cacb->hash_size == 1 &&
177 gnc_commodity_equal(cmdty, xaccAccountGetCommodity(cacb->base_acct)))
178 acc = cacb->base_acct;
179 else
180 {
181 /* See if we already have an account by that name */
182 acc = gnc_account_lookup_by_name(cacb->base_acct,
184
185 /* If not, then create one */
186 if (!acc)
187 {
188 acc = xaccMallocAccount(cacb->cbw->book);
190 xaccAccountSetType(acc, ACCT_TYPE_EQUITY);
193 xaccAccountSetCommodity(acc, cmdty);
194 gnc_account_append_child(cacb->base_acct, acc);
196 }
197 }
198 /* Make sure the account exists and is of the correct commodity */
199 g_assert(acc);
200 g_assert(gnc_commodity_equal(cmdty, xaccAccountGetCommodity(acc)));
201
202 /* Create the split for the Equity account to balance out
203 * all the accounts of this. Use the "total".
204 */
205 split = xaccMallocSplit(cacb->cbw->book);
206 xaccSplitSetParent(split, txn->txn);
208 xaccAccountInsertSplit(acc, split);
209 xaccSplitSetBaseValue(split, txn->total, cmdty);
211 xaccTransCommitEdit(txn->txn);
212}
213
214static void close_accounts_of_type(struct CloseBookWindow* cbw,
215 Account* acct,
216 GNCAccountType acct_type)
217{
218 struct CloseAccountsCB cacb;
219 Account* root_acct;
220
221 g_return_if_fail(cbw);
222 g_return_if_fail(acct);
223
224 cacb.cbw = cbw;
225 cacb.base_acct = acct;
226 cacb.acct_type = acct_type;
227 cacb.txns = g_hash_table_new_full(g_direct_hash,
228 (GEqualFunc)gnc_commodity_equal,
229 NULL, g_free);
230
231 /* Iterate through all accounts and set up the balancing splits */
232 root_acct = gnc_book_get_root_account(cbw->book);
233 gnc_account_foreach_descendant(root_acct, close_accounts_cb, &cacb);
234
235 /* now iterate through the transactions and handle each currency */
236 cacb.hash_size = g_hash_table_size(cacb.txns);
237 if (cacb.hash_size)
238 g_hash_table_foreach(cacb.txns, (GHFunc)finish_txn_cb, &cacb);
239
240 /* Destroy the table, freeing the used memory */
241 g_hash_table_destroy(cacb.txns);
242}
243
244static void close_handler(gpointer data)
245{
246 GtkWidget *dialog = data;
247
248 gtk_widget_destroy(dialog);
249}
250
251static void destroy_cb(GObject *object, gpointer data)
252{
253 struct CloseBookWindow *cbw;
254
255 cbw = g_object_get_data(G_OBJECT(object), "CloseBookWindow");
256
257 if (cbw->component_manager_id)
258 {
259 gnc_unregister_gui_component(cbw->component_manager_id);
260 cbw->component_manager_id = 0;
261 }
262}
263
264
265void
266gnc_book_close_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused)
267{
268 struct CloseBookWindow* cbw;
269 Account* income_acct;
270 Account* expense_acct;
271
272 ENTER("dialog %p, response %d, unused %p", dialog, response, unused);
273
274 g_return_if_fail(dialog);
275
276 cbw = g_object_get_data(G_OBJECT(dialog), "CloseBookWindow");
277 g_return_if_fail(cbw);
278
279 switch (response)
280 {
281 case GTK_RESPONSE_HELP:
282 gnc_gnome_help (GTK_WINDOW(dialog), DF_MANUAL, DL_CLOSE_BOOK);
283 break;
284 case GTK_RESPONSE_OK:
285 cbw->close_date = gnc_date_edit_get_date(GNC_DATE_EDIT(cbw->close_date_widget));
286 cbw->desc = gtk_entry_get_text(GTK_ENTRY(cbw->desc_widget));
287
288 income_acct = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(cbw->income_acct_widget));
289 expense_acct = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(cbw->expense_acct_widget));
290
291 if (!income_acct)
292 {
293 gnc_error_dialog(GTK_WINDOW (cbw->dialog), "%s",
294 _("Please select an Equity account to hold the total Period Income."));
295 break;
296 }
297
298 if (!expense_acct)
299 {
300 gnc_error_dialog(GTK_WINDOW (cbw->dialog), "%s",
301 _("Please select an Equity account to hold the total Period Expense."));
302 break;
303 }
304
305 gnc_suspend_gui_refresh();
306 close_accounts_of_type(cbw, income_acct, ACCT_TYPE_INCOME);
307 close_accounts_of_type(cbw, expense_acct, ACCT_TYPE_EXPENSE);
308 gnc_resume_gui_refresh();
309
310 /* FALL THROUGH */
311 default:
312 gtk_widget_destroy(GTK_WIDGET(dialog));
313 break;
314 }
315 LEAVE("");
316}
317
318void gnc_ui_close_book (QofBook* book, GtkWindow *parent)
319{
320 struct CloseBookWindow *cbw;
321 GtkBuilder* builder;
322 GtkWidget* box;
323 GList* equity_list = NULL;
324
325 g_return_if_fail(book);
326
327 cbw = g_new0(struct CloseBookWindow, 1);
328 g_return_if_fail(cbw);
329 cbw->book = book;
330
331 /* Open the dialog */
332 builder = gtk_builder_new();
333 gnc_builder_add_from_file (builder, "dialog-book-close.glade", "close_book_dialog");
334 cbw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "close_book_dialog"));
335
336 // Set the name for this dialog so it can be easily manipulated with css
337 gtk_widget_set_name (GTK_WIDGET(cbw->dialog), "gnc-id-book-close");
338
339 /* parent */
340 if (parent != NULL)
341 gtk_window_set_transient_for (GTK_WINDOW(cbw->dialog), GTK_WINDOW(parent));
342
343 PINFO("Closed Book Window is %p, Dialog is %p", cbw, cbw->dialog);
344
345 /* close date */
346 box = GTK_WIDGET(gtk_builder_get_object (builder, "date_box"));
347 cbw->close_date_widget = gnc_date_edit_new(gnc_time (NULL), FALSE, FALSE);
348 gtk_box_pack_start(GTK_BOX(box), cbw->close_date_widget, TRUE, TRUE, 0);
349
350 /* income acct */
351 equity_list = g_list_prepend(equity_list, GINT_TO_POINTER(ACCT_TYPE_EQUITY));
352 box = GTK_WIDGET(gtk_builder_get_object (builder, "income_acct_box"));
353 cbw->income_acct_widget = gnc_account_sel_new();
354 gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(cbw->income_acct_widget),
355 equity_list, NULL);
356 gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(cbw->income_acct_widget), TRUE);
357 gtk_box_pack_start(GTK_BOX(box), cbw->income_acct_widget, TRUE, TRUE, 0);
358
359 /* expense acct */
360 box = GTK_WIDGET(gtk_builder_get_object (builder, "expense_acct_box"));
361 cbw->expense_acct_widget = gnc_account_sel_new();
362 gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(cbw->expense_acct_widget),
363 equity_list, NULL);
364 gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(cbw->expense_acct_widget), TRUE);
365 gtk_box_pack_start(GTK_BOX(box), cbw->expense_acct_widget, TRUE, TRUE, 0);
366
367 /* desc */
368 cbw->desc_widget = GTK_WIDGET(gtk_builder_get_object (builder, "desc_entry"));
369
370 /* Autoconnect signals */
371 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, cbw->dialog);
372
373 /* Register dialog with component manager */
374 cbw->component_manager_id =
375 gnc_register_gui_component(DIALOG_BOOK_CLOSE_CM_CLASS, NULL, close_handler,
376 cbw->dialog);
377 gnc_gui_component_set_session(cbw->component_manager_id,
378 gnc_get_current_session());
379 g_signal_connect(cbw->dialog, "destroy", G_CALLBACK(destroy_cb), NULL);
380
381 /* Clean up the data structure when the dialog is destroyed */
382 g_object_set_data_full(G_OBJECT(cbw->dialog), "CloseBookWindow", cbw, g_free);
383
384 g_object_unref(G_OBJECT(builder));
385
386 /* Run the dialog */
387 gtk_widget_show_all(cbw->dialog);
388
389 g_list_free(equity_list);
390}
391
Account handling public routines.
API for Transactions and Splits (journal entries)
API for Transactions and Splits (journal entries)
This file contains the functions to present a GUI to select a book closing date and accounts into whi...
All type declarations for the whole Gnucash engine.
utility functions for the GnuCash UI
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
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed.
Definition Account.h:103
void gnc_account_append_child(Account *new_parent, Account *child)
This function will remove from the child account any pre-existing parent relationship,...
Definition Account.cpp:2836
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3267
void xaccAccountSetName(Account *acc, const char *str)
Set the account's name.
Definition Account.cpp:2458
gnc_numeric xaccAccountGetBalanceAsOfDate(Account *acc, time64 date)
Get the balance of the account at the end of the day before the date specified.
Definition Account.cpp:3533
void xaccAccountSetDescription(Account *acc, const char *str)
Set the account's description.
Definition Account.cpp:2497
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Set the account's type.
Definition Account.cpp:2437
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition Account.cpp:1270
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
@ ACCT_TYPE_EQUITY
Equity account is used to balance the balance sheet.
Definition Account.h:146
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gnc_time64_get_day_end(time64 time_val)
The gnc_time64_get_day_end() routine will take the given time in seconds and adjust it to the last se...
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
void xaccTransSetIsClosingTxn(Transaction *trans, gboolean is_closing)
Sets whether or not this transaction is a "closing transaction".
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
The gnc_account_lookup_by_name() subroutine fetches the account by name from the descendants of the s...
Definition Account.cpp:3093
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3)).
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account.
Definition Account.h:1069
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
void gnc_ui_close_book(QofBook *book, GtkWindow *parent)
Create and run the dialog to close the book.
void gnc_gnome_help(GtkWindow *parent, const char *file_name, const char *anchor)
Launch the systems default help browser, gnome's yelp for linux, and open to a given link within a gi...
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Returns a gnc_commodity that is a currency, suitable for being a Transaction's currency.
#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
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
Split * xaccMallocSplit(QofBook *book)
Constructor.
void xaccSplitSetBaseValue(Split *s, gnc_numeric value, const gnc_commodity *base_currency)
Depending on the base_currency, set either the value or the amount of this split or both: If the base...
Definition Split.cpp:1355
STRUCTS.
QofBook reference.
Definition qofbook-p.hpp:47