00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "config.h"
00028
00029 #include <gtk/gtk.h>
00030 #include <glib/gi18n.h>
00031 #include <glade/glade.h>
00032
00033 #include "dialog-utils.h"
00034 #include "gnc-engine.h"
00035 #include "Transaction.h"
00036 #include "Split.h"
00037 #include "Account.h"
00038 #include "gnc-ui.h"
00039 #include "gnc-gui-query.h"
00040 #include "dialog-book-close.h"
00041 #include "gnc-account-sel.h"
00042 #include "gnc-component-manager.h"
00043 #include "gnc-date-edit.h"
00044 #include "gnc-session.h"
00045
00046 #define DIALOG_BOOK_CLOSE_CM_CLASS "dialog-book-close"
00047
00048 void gnc_book_close_response_cb(GtkDialog *, gint, GtkDialog *);
00049
00050 struct CloseBookWindow
00051 {
00052
00053 QofBook* book;
00054
00055
00056 GtkWidget* dialog;
00057 GtkWidget* close_date_widget;
00058 GtkWidget* income_acct_widget;
00059 GtkWidget* expense_acct_widget;
00060 GtkWidget* desc_widget;
00061
00062
00063 time_t close_date;
00064 const char* desc;
00065
00066
00067 gint component_manager_id;
00068 };
00069
00070 struct CloseAccountsCB
00071 {
00072 struct CloseBookWindow* cbw;
00073 Account* base_acct;
00074 GNCAccountType acct_type;
00075 GHashTable* txns;
00076 guint hash_size;
00077 };
00078
00079 struct CACBTransactionList
00080 {
00081 gnc_commodity* cmdty;
00082 Transaction* txn;
00083 gnc_numeric total;
00084 };
00085
00086 static struct CACBTransactionList*
00087 find_or_create_txn(struct CloseAccountsCB* cacb, gnc_commodity* cmdty)
00088 {
00089 struct CACBTransactionList* txn;
00090
00091 g_return_val_if_fail(cacb, NULL);
00092 g_return_val_if_fail(cmdty, NULL);
00093
00094 txn = g_hash_table_lookup(cacb->txns, cmdty);
00095 if (!txn)
00096 {
00097 kvp_frame* frame;
00098 txn = g_new0(struct CACBTransactionList, 1);
00099 txn->cmdty = cmdty;
00100 txn->total = gnc_numeric_zero();
00101 txn->txn = xaccMallocTransaction(cacb->cbw->book);
00102 xaccTransBeginEdit(txn->txn);
00103 xaccTransSetDateEnteredSecs(txn->txn, time(NULL));
00104 xaccTransSetDatePostedSecs(txn->txn, cacb->cbw->close_date);
00105 xaccTransSetDescription(txn->txn, cacb->cbw->desc);
00106 xaccTransSetCurrency(txn->txn, cmdty);
00107 xaccTransSetIsClosingTxn(txn->txn, TRUE);
00108 g_hash_table_insert(cacb->txns, cmdty, txn);
00109 }
00110
00111 return txn;
00112 }
00113
00114
00115
00116
00117
00118
00119
00120 static void close_accounts_cb(Account *a, gpointer data)
00121 {
00122 struct CloseAccountsCB* cacb = data;
00123 struct CACBTransactionList* txn;
00124 gnc_commodity* acct_commodity;
00125 Split* split;
00126 gnc_numeric bal;
00127
00128 g_return_if_fail(a);
00129 g_return_if_fail(cacb);
00130 g_return_if_fail(cacb->cbw);
00131 g_return_if_fail(cacb->txns);
00132
00133 if (cacb->acct_type != xaccAccountGetType(a))
00134 return;
00135
00136 bal = xaccAccountGetBalanceAsOfDate(a, cacb->cbw->close_date + 1);
00137 if (gnc_numeric_zero_p(bal))
00138 return;
00139
00140 acct_commodity = xaccAccountGetCommodity(a);
00141 g_assert(acct_commodity);
00142
00143 txn = find_or_create_txn(cacb, acct_commodity);
00144 g_assert(txn);
00145
00146 split = xaccMallocSplit(cacb->cbw->book);
00147 xaccSplitSetParent(split, txn->txn);
00148 xaccAccountBeginEdit(a);
00149 xaccAccountInsertSplit(a, split);
00150 xaccSplitSetBaseValue(split, gnc_numeric_neg(bal), acct_commodity);
00151 xaccAccountCommitEdit(a);
00152 txn->total = gnc_numeric_add(txn->total, bal, GNC_DENOM_AUTO,
00153 GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
00154 }
00155
00156
00157 static void finish_txn_cb(gnc_commodity* cmdty,
00158 struct CACBTransactionList* txn,
00159 struct CloseAccountsCB* cacb)
00160 {
00161 Account* acc;
00162 Split* split;
00163
00164 g_return_if_fail(cmdty);
00165 g_return_if_fail(txn);
00166 g_return_if_fail(cacb);
00167 g_return_if_fail(cacb->hash_size);
00168
00169
00170
00171
00172
00173 if (cacb->hash_size == 1 &&
00174 gnc_commodity_equal(cmdty, xaccAccountGetCommodity(cacb->base_acct)))
00175 acc = cacb->base_acct;
00176 else
00177 {
00178
00179 acc = gnc_account_lookup_by_name(cacb->base_acct,
00180 gnc_commodity_get_mnemonic(cmdty));
00181
00182
00183 if (!acc)
00184 {
00185 acc = xaccMallocAccount(cacb->cbw->book);
00186 xaccAccountBeginEdit(acc);
00187 xaccAccountSetType(acc, ACCT_TYPE_EQUITY);
00188 xaccAccountSetName(acc, gnc_commodity_get_mnemonic(cmdty));
00189 xaccAccountSetDescription(acc, gnc_commodity_get_mnemonic(cmdty));
00190 xaccAccountSetCommodity(acc, cmdty);
00191 gnc_account_append_child(cacb->base_acct, acc);
00192 xaccAccountCommitEdit(acc);
00193 }
00194 }
00195
00196 g_assert(acc);
00197 g_assert(gnc_commodity_equal(cmdty, xaccAccountGetCommodity(acc)));
00198
00199
00200
00201
00202 split = xaccMallocSplit(cacb->cbw->book);
00203 xaccSplitSetParent(split, txn->txn);
00204 xaccAccountBeginEdit(acc);
00205 xaccAccountInsertSplit(acc, split);
00206 xaccSplitSetBaseValue(split, txn->total, cmdty);
00207 xaccAccountCommitEdit(acc);
00208 xaccTransCommitEdit(txn->txn);
00209 }
00210
00211 static void close_accounts_of_type(struct CloseBookWindow* cbw,
00212 Account* acct,
00213 GNCAccountType acct_type)
00214 {
00215 struct CloseAccountsCB cacb;
00216 Account* root_acct;
00217
00218 g_return_if_fail(cbw);
00219 g_return_if_fail(acct);
00220
00221 cacb.cbw = cbw;
00222 cacb.base_acct = acct;
00223 cacb.acct_type = acct_type;
00224 cacb.txns = g_hash_table_new_full(g_direct_hash,
00225 (GEqualFunc)gnc_commodity_equal,
00226 NULL, g_free);
00227
00228
00229 root_acct = gnc_book_get_root_account(cbw->book);
00230 gnc_account_foreach_descendant(root_acct, close_accounts_cb, &cacb);
00231
00232
00233 cacb.hash_size = g_hash_table_size(cacb.txns);
00234 if (cacb.hash_size)
00235 g_hash_table_foreach(cacb.txns, (GHFunc)finish_txn_cb, &cacb);
00236
00237
00238 g_hash_table_destroy(cacb.txns);
00239 }
00240
00241 static void close_handler(gpointer data)
00242 {
00243 GtkWidget *dialog = data;
00244
00245 gtk_widget_destroy(dialog);
00246 }
00247
00248 static void destroy_cb(GtkObject *object, gpointer data)
00249 {
00250 struct CloseBookWindow *cbw;
00251
00252 cbw = g_object_get_data(G_OBJECT(object), "CloseBookWindow");
00253
00254 if (cbw->component_manager_id)
00255 {
00256 gnc_unregister_gui_component(cbw->component_manager_id);
00257 cbw->component_manager_id = 0;
00258 }
00259 }
00260
00261
00262 void
00263 gnc_book_close_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused)
00264 {
00265 struct CloseBookWindow* cbw;
00266 Account* income_acct;
00267 Account* expense_acct;
00268
00269 g_return_if_fail(dialog);
00270
00271 cbw = g_object_get_data(G_OBJECT(dialog), "CloseBookWindow");
00272 g_return_if_fail(cbw);
00273
00274 switch (response)
00275 {
00276 case GTK_RESPONSE_HELP:
00277 gnc_gnome_help(HF_HELP, HL_GLOBPREFS);
00278 break;
00279 case GTK_RESPONSE_OK:
00280 cbw->close_date = gnc_date_edit_get_date(GNC_DATE_EDIT(cbw->close_date_widget));
00281 cbw->close_date += (3600 * 12);
00282 cbw->desc = gtk_entry_get_text(GTK_ENTRY(cbw->desc_widget));
00283
00284 income_acct = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(cbw->income_acct_widget));
00285 expense_acct = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(cbw->expense_acct_widget));
00286
00287 if (!income_acct)
00288 {
00289 gnc_error_dialog(cbw->dialog, "%s",
00290 _("Please select an Equity account to hold the total Period Income."));
00291 break;
00292 }
00293
00294 if (!expense_acct)
00295 {
00296 gnc_error_dialog(cbw->dialog, "%s",
00297 _("Please select an Equity account to hold the total Period Expense."));
00298 break;
00299 }
00300
00301 gnc_suspend_gui_refresh();
00302 close_accounts_of_type(cbw, income_acct, ACCT_TYPE_INCOME);
00303 close_accounts_of_type(cbw, expense_acct, ACCT_TYPE_EXPENSE);
00304 gnc_resume_gui_refresh();
00305
00306
00307 default:
00308 gtk_widget_destroy(GTK_WIDGET(dialog));
00309 break;
00310 }
00311 }
00312
00313 void gnc_ui_close_book (QofBook* book)
00314 {
00315 struct CloseBookWindow *cbw;
00316 GladeXML* xml;
00317 GtkWidget* box;
00318 GList* equity_list = NULL;
00319
00320 g_return_if_fail(book);
00321
00322 cbw = g_new0(struct CloseBookWindow, 1);
00323 g_return_if_fail(cbw);
00324 cbw->book = book;
00325
00326
00327 xml = gnc_glade_xml_new("dialog-book-close.glade", "Close Book");
00328 cbw->dialog = glade_xml_get_widget(xml, "Close Book");
00329
00330
00331 box = glade_xml_get_widget(xml, "date_box");
00332 cbw->close_date_widget = gnc_date_edit_new(time(NULL), FALSE, FALSE);
00333 gtk_box_pack_start(GTK_BOX(box), cbw->close_date_widget, TRUE, TRUE, 0);
00334
00335
00336 equity_list = g_list_prepend(equity_list, GINT_TO_POINTER(ACCT_TYPE_EQUITY));
00337 box = glade_xml_get_widget(xml, "income_acct_box");
00338 cbw->income_acct_widget = gnc_account_sel_new();
00339 gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(cbw->income_acct_widget),
00340 equity_list, NULL);
00341 gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(cbw->income_acct_widget), TRUE);
00342 gtk_box_pack_start(GTK_BOX(box), cbw->income_acct_widget, TRUE, TRUE, 0);
00343
00344
00345 box = glade_xml_get_widget(xml, "expense_acct_box");
00346 cbw->expense_acct_widget = gnc_account_sel_new();
00347 gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(cbw->expense_acct_widget),
00348 equity_list, NULL);
00349 gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(cbw->expense_acct_widget), TRUE);
00350 gtk_box_pack_start(GTK_BOX(box), cbw->expense_acct_widget, TRUE, TRUE, 0);
00351
00352
00353 cbw->desc_widget = glade_xml_get_widget(xml, "desc_entry");
00354
00355
00356 glade_xml_signal_autoconnect_full(xml, gnc_glade_autoconnect_full_func,
00357 cbw->dialog);
00358
00359
00360 cbw->component_manager_id =
00361 gnc_register_gui_component(DIALOG_BOOK_CLOSE_CM_CLASS, NULL, close_handler,
00362 cbw->dialog);
00363 gnc_gui_component_set_session(cbw->component_manager_id,
00364 gnc_get_current_session());
00365 g_signal_connect(cbw->dialog, "destroy", G_CALLBACK(destroy_cb), NULL);
00366
00367
00368 g_object_set_data_full(G_OBJECT(cbw->dialog), "dialog-book-close.glade",
00369 xml, g_object_unref);
00370 g_object_set_data_full(G_OBJECT(cbw->dialog), "CloseBookWindow", cbw,
00371 g_free);
00372
00373
00374 gtk_widget_show_all(cbw->dialog);
00375
00376 g_list_free(equity_list);
00377 }
00378