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 txn = g_new0(struct CACBTransactionList, 1);
00098 txn->cmdty = cmdty;
00099 txn->total = gnc_numeric_zero();
00100 txn->txn = xaccMallocTransaction(cacb->cbw->book);
00101 xaccTransBeginEdit(txn->txn);
00102 xaccTransSetDateEnteredSecs(txn->txn, time(NULL));
00103 xaccTransSetDatePostedSecs(txn->txn, cacb->cbw->close_date);
00104 xaccTransSetDescription(txn->txn, cacb->cbw->desc);
00105 xaccTransSetCurrency(txn->txn, cmdty);
00106
00107 g_hash_table_insert(cacb->txns, cmdty, txn);
00108 }
00109
00110 return txn;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119 static void close_accounts_cb(Account *a, gpointer data)
00120 {
00121 struct CloseAccountsCB* cacb = data;
00122 struct CACBTransactionList* txn;
00123 gnc_commodity* acct_commodity;
00124 Split* split;
00125 gnc_numeric bal;
00126
00127 g_return_if_fail(a);
00128 g_return_if_fail(cacb);
00129 g_return_if_fail(cacb->cbw);
00130 g_return_if_fail(cacb->txns);
00131
00132 if (cacb->acct_type != xaccAccountGetType(a))
00133 return;
00134
00135 bal = xaccAccountGetBalanceAsOfDate(a, cacb->cbw->close_date+1);
00136 if (gnc_numeric_zero_p(bal))
00137 return;
00138
00139 acct_commodity = xaccAccountGetCommodity(a);
00140 g_assert(acct_commodity);
00141
00142 txn = find_or_create_txn(cacb, acct_commodity);
00143 g_assert(txn);
00144
00145 split = xaccMallocSplit(cacb->cbw->book);
00146 xaccSplitSetParent(split, txn->txn);
00147 xaccAccountBeginEdit(a);
00148 xaccAccountInsertSplit(a, split);
00149 xaccSplitSetBaseValue(split, gnc_numeric_neg(bal), acct_commodity);
00150 xaccAccountCommitEdit(a);
00151 txn->total = gnc_numeric_add(txn->total, bal, GNC_DENOM_AUTO,
00152 GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
00153 }
00154
00155
00156 static void finish_txn_cb(gnc_commodity* cmdty,
00157 struct CACBTransactionList* txn,
00158 struct CloseAccountsCB* cacb)
00159 {
00160 Account* acc;
00161 Split* split;
00162
00163 g_return_if_fail(cmdty);
00164 g_return_if_fail(txn);
00165 g_return_if_fail(cacb);
00166 g_return_if_fail(cacb->hash_size);
00167
00168
00169
00170
00171
00172 if (cacb->hash_size == 1 &&
00173 gnc_commodity_equal(cmdty, xaccAccountGetCommodity(cacb->base_acct)))
00174 acc = cacb->base_acct;
00175 else
00176 {
00177
00178 acc = gnc_account_lookup_by_name(cacb->base_acct,
00179 gnc_commodity_get_mnemonic(cmdty));
00180
00181
00182 if (!acc)
00183 {
00184 acc = xaccMallocAccount(cacb->cbw->book);
00185 xaccAccountBeginEdit(acc);
00186 xaccAccountSetType(acc, ACCT_TYPE_EQUITY);
00187 xaccAccountSetName(acc, gnc_commodity_get_mnemonic(cmdty));
00188 xaccAccountSetDescription(acc, gnc_commodity_get_mnemonic(cmdty));
00189 xaccAccountSetCommodity(acc, cmdty);
00190 gnc_account_append_child(cacb->base_acct, acc);
00191 xaccAccountCommitEdit(acc);
00192 }
00193 }
00194
00195 g_assert(acc);
00196 g_assert(gnc_commodity_equal(cmdty, xaccAccountGetCommodity(acc)));
00197
00198
00199
00200
00201 split = xaccMallocSplit(cacb->cbw->book);
00202 xaccSplitSetParent(split, txn->txn);
00203 xaccAccountBeginEdit(acc);
00204 xaccAccountInsertSplit(acc, split);
00205 xaccSplitSetBaseValue(split, txn->total, cmdty);
00206 xaccAccountCommitEdit(acc);
00207 xaccTransCommitEdit(txn->txn);
00208 }
00209
00210 static void close_accounts_of_type(struct CloseBookWindow* cbw,
00211 Account* acct,
00212 GNCAccountType acct_type)
00213 {
00214 struct CloseAccountsCB cacb;
00215 Account* root_acct;
00216
00217 g_return_if_fail(cbw);
00218 g_return_if_fail(acct);
00219
00220 cacb.cbw = cbw;
00221 cacb.base_acct = acct;
00222 cacb.acct_type = acct_type;
00223 cacb.txns = g_hash_table_new_full(g_direct_hash,
00224 (GEqualFunc)gnc_commodity_equal,
00225 NULL, g_free);
00226
00227
00228 root_acct = gnc_book_get_root_account(cbw->book);
00229 gnc_account_foreach_descendant(root_acct, close_accounts_cb, &cacb);
00230
00231
00232 cacb.hash_size = g_hash_table_size(cacb.txns);
00233 if (cacb.hash_size)
00234 g_hash_table_foreach(cacb.txns, (GHFunc)finish_txn_cb, &cacb);
00235
00236
00237 g_hash_table_destroy(cacb.txns);
00238 }
00239
00240 static void close_handler(gpointer data)
00241 {
00242 GtkWidget *dialog = data;
00243
00244 gtk_widget_destroy(dialog);
00245 }
00246
00247 static void destroy_cb(GtkObject *object, gpointer data)
00248 {
00249 struct CloseBookWindow *cbw;
00250
00251 cbw = g_object_get_data(G_OBJECT(object), "CloseBookWindow");
00252
00253 if (cbw->component_manager_id) {
00254 gnc_unregister_gui_component(cbw->component_manager_id);
00255 cbw->component_manager_id = 0;
00256 }
00257 }
00258
00259
00260 void
00261 gnc_book_close_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused)
00262 {
00263 struct CloseBookWindow* cbw;
00264 Account* income_acct;
00265 Account* expense_acct;
00266
00267 g_return_if_fail(dialog);
00268
00269 cbw = g_object_get_data(G_OBJECT(dialog), "CloseBookWindow");
00270 g_return_if_fail(cbw);
00271
00272 switch (response)
00273 {
00274 case GTK_RESPONSE_HELP:
00275 gnc_gnome_help(HF_HELP, HL_GLOBPREFS);
00276 break;
00277 case GTK_RESPONSE_OK:
00278 cbw->close_date = gnc_date_edit_get_date(GNC_DATE_EDIT(cbw->close_date_widget));
00279 cbw->close_date += (3600 * 12);
00280 cbw->desc = gtk_entry_get_text(GTK_ENTRY(cbw->desc_widget));
00281
00282 income_acct = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(cbw->income_acct_widget));
00283 expense_acct = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(cbw->expense_acct_widget));
00284
00285 if (!income_acct)
00286 {
00287 gnc_error_dialog(cbw->dialog, "%s",
00288 _("Please select an Equity account to hold the total Period Income."));
00289 break;
00290 }
00291
00292 if (!expense_acct)
00293 {
00294 gnc_error_dialog(cbw->dialog, "%s",
00295 _("Please select an Equity account to hold the total Period Expense."));
00296 break;
00297 }
00298
00299 close_accounts_of_type(cbw, income_acct, ACCT_TYPE_INCOME);
00300 close_accounts_of_type(cbw, expense_acct, ACCT_TYPE_EXPENSE);
00301
00302
00303 default:
00304 gtk_widget_destroy(GTK_WIDGET(dialog));
00305 break;
00306 }
00307 }
00308
00309 void gnc_ui_close_book (QofBook* book)
00310 {
00311 struct CloseBookWindow *cbw;
00312 GladeXML* xml;
00313 GtkWidget* box;
00314 GList* equity_list = NULL;
00315
00316 g_return_if_fail(book);
00317
00318 cbw = g_new0(struct CloseBookWindow, 1);
00319 g_return_if_fail(cbw);
00320 cbw->book = book;
00321
00322
00323 xml = gnc_glade_xml_new("dialog-book-close.glade", "Close Book");
00324 cbw->dialog = glade_xml_get_widget(xml, "Close Book");
00325
00326
00327 box = glade_xml_get_widget(xml, "date_box");
00328 cbw->close_date_widget = gnc_date_edit_new(time(NULL), FALSE, FALSE);
00329 gtk_box_pack_start(GTK_BOX(box), cbw->close_date_widget, TRUE, TRUE, 0);
00330
00331
00332 equity_list = g_list_prepend(equity_list, GINT_TO_POINTER(ACCT_TYPE_EQUITY));
00333 box = glade_xml_get_widget(xml, "income_acct_box");
00334 cbw->income_acct_widget = gnc_account_sel_new();
00335 gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(cbw->income_acct_widget),
00336 equity_list);
00337 gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(cbw->income_acct_widget), TRUE);
00338 gtk_box_pack_start(GTK_BOX(box), cbw->income_acct_widget, TRUE, TRUE, 0);
00339
00340
00341 box = glade_xml_get_widget(xml, "expense_acct_box");
00342 cbw->expense_acct_widget = gnc_account_sel_new();
00343 gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(cbw->expense_acct_widget),
00344 equity_list);
00345 gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(cbw->expense_acct_widget), TRUE);
00346 gtk_box_pack_start(GTK_BOX(box), cbw->expense_acct_widget, TRUE, TRUE, 0);
00347
00348
00349 cbw->desc_widget = glade_xml_get_widget(xml, "desc_entry");
00350
00351
00352 glade_xml_signal_autoconnect_full(xml, gnc_glade_autoconnect_full_func,
00353 cbw->dialog);
00354
00355
00356 cbw->component_manager_id =
00357 gnc_register_gui_component(DIALOG_BOOK_CLOSE_CM_CLASS, NULL, close_handler,
00358 cbw->dialog);
00359 gnc_gui_component_set_session(cbw->component_manager_id,
00360 gnc_get_current_session());
00361 g_signal_connect(cbw->dialog, "destroy", G_CALLBACK(destroy_cb), NULL);
00362
00363
00364 g_object_set_data_full(G_OBJECT(cbw->dialog), "dialog-book-close.glade",
00365 xml, g_object_unref);
00366 g_object_set_data_full(G_OBJECT(cbw->dialog), "CloseBookWindow", cbw,
00367 g_free);
00368
00369
00370 gtk_widget_show_all(cbw->dialog);
00371
00372 g_list_free(equity_list);
00373 }
00374