GnuCash 2.4.99
gncEntryLedgerLoad.c
00001 /*
00002  * gncEntryLedgerLoad.c -- a Ledger widget for entering GncEntry objects
00003  * Copyright (C) 2001, 2002, 2003 Derek Atkins
00004  * Author: Derek Atkins <warlord@MIT.EDU>
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License as
00008  * published by the Free Software Foundation; either version 2 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, contact:
00018  *
00019  * Free Software Foundation           Voice:  +1-617-542-5942
00020  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00021  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00022  */
00023 
00024 #include "config.h"
00025 
00026 #include <glib.h>
00027 #include <glib/gi18n.h>
00028 #include <libguile.h>
00029 
00030 #include "Account.h"
00031 #include "account-quickfill.h"
00032 #include "combocell.h"
00033 #include "gnc-component-manager.h"
00034 #include "gnc-gconf-utils.h"
00035 #include "gnc-ui-util.h"
00036 #include "recncell.h"
00037 
00038 #include "business-options.h"
00039 
00040 #include "gncEntry.h"
00041 #include "gncEntryLedger.h"
00042 #include "gncEntryLedgerP.h"
00043 #include "quickfillcell.h"
00044 #include "app-utils/gnc-entry-quickfill.h"
00045 
00046 
00047 /* XXX: This should go elsewhere */
00048 const char * gnc_entry_ledger_type_string_getter (char flag)
00049 {
00050     switch (flag)
00051     {
00052     case '1':
00053         return _("$");
00054     case '2':
00055         return _("%");
00056     default:
00057         return "?";
00058     };
00059 }
00060 
00061 const char * gnc_entry_ledger_how_string_getter (char flag)
00062 {
00063     switch (flag)
00064     {
00065     case '1':
00066         return _("<");
00067     case '2':
00068         return _("=");
00069     case '3':
00070         return _(">");
00071     default:
00072         return "?";
00073     };
00074 }
00075 
00076 static void load_discount_type_cells (GncEntryLedger *ledger)
00077 {
00078     RecnCell *cell;
00079 
00080     if (!ledger) return;
00081 
00082     cell = (RecnCell *)
00083            gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISTYPE_CELL);
00084 
00085     if (!cell) return;
00086 
00087     gnc_recn_cell_set_valid_flags (cell, "12", '2');
00088     gnc_recn_cell_set_flag_order (cell, "21");
00089     gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_type_string_getter);
00090 }
00091 
00092 static void load_discount_how_cells (GncEntryLedger *ledger)
00093 {
00094     RecnCell *cell;
00095 
00096     if (!ledger) return;
00097 
00098     cell = (RecnCell *)
00099            gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISHOW_CELL);
00100 
00101     if (!cell) return;
00102 
00103     gnc_recn_cell_set_valid_flags (cell, "123", '1');
00104     gnc_recn_cell_set_flag_order (cell, "123");
00105     gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_how_string_getter);
00106 }
00107 
00108 static void load_payment_type_cells (GncEntryLedger *ledger)
00109 {
00110     ComboCell *cell;
00111     const GncOwner *owner;
00112     GncEmployee *employee;
00113 
00114     cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
00115             ENTRY_PAYMENT_CELL);
00116     if (!cell) return;
00117 
00118     if (!ledger->invoice) return;
00119 
00120     owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
00121     if (gncOwnerGetType (owner) != GNC_OWNER_EMPLOYEE)
00122         return;
00123 
00124     employee = gncOwnerGetEmployee (owner);
00125     g_return_if_fail (employee);
00126 
00127     gnc_combo_cell_clear_menu (cell);
00128     gnc_combo_cell_add_menu_item (cell, _("Cash"));
00129 
00130     if (gncEmployeeGetCCard (employee))
00131         gnc_combo_cell_add_menu_item (cell, _("Charge"));
00132 }
00133 
00134 /* ==================================================================== */
00135 /* Return TRUE if we don't want to add this account to the xfer menu */
00136 
00137 static gboolean
00138 skip_expense_acct_cb (Account *account, gpointer user_data)
00139 {
00140     GNCAccountType type;
00141 
00142     /* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
00143     type = xaccAccountGetType (account);
00144     if (type == ACCT_TYPE_PAYABLE || type == ACCT_TYPE_RECEIVABLE ||
00145             type == ACCT_TYPE_CASH || type == ACCT_TYPE_BANK ||
00146             type == ACCT_TYPE_EQUITY || type == ACCT_TYPE_TRADING)
00147     {
00148         return TRUE;
00149     }
00150 
00151     /* If this is an ORDER or INVOICE, then leave out the expenses.  */
00152     if (type == ACCT_TYPE_EXPENSE) return TRUE;
00153 
00154     /* Don't add placeholder accounts */
00155     if (xaccAccountGetPlaceholder (account)) return TRUE;
00156 
00157     return FALSE;
00158 }
00159 
00160 static gboolean
00161 skip_income_acct_cb (Account *account, gpointer user_data)
00162 {
00163     GNCAccountType type;
00164 
00165     /* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
00166     type = xaccAccountGetType (account);
00167     if (type == ACCT_TYPE_PAYABLE || type == ACCT_TYPE_RECEIVABLE ||
00168             type == ACCT_TYPE_CASH || type == ACCT_TYPE_BANK ||
00169             type == ACCT_TYPE_EQUITY || type == ACCT_TYPE_TRADING)
00170     {
00171         return TRUE;
00172     }
00173 
00174     /* If this is a BILL, then leave out the incomes */
00175     if (type == ACCT_TYPE_INCOME) return TRUE;
00176 
00177     /* Don't add placeholder accounts */
00178     if (xaccAccountGetPlaceholder (account)) return TRUE;
00179 
00180     return FALSE;
00181 }
00182 
00183 /* ===================================================================== */
00184 /* Splat the account name into the transfer cell combobox menu */
00185 
00186 #define EKEY "Expense Business entry quickfill"
00187 #define IKEY "Income Business entry quickfill"
00188 
00189 static void
00190 load_xfer_type_cells (GncEntryLedger *ledger)
00191 {
00192     Account *root;
00193     ComboCell *cell;
00194     QuickFill *qf = NULL;
00195     GtkListStore *store = NULL;
00196 
00197     root = gnc_book_get_root_account (ledger->book);
00198     if (root == NULL) return;
00199 
00200     /* Use a common, shared quickfill.  For the ORDER or INVOICE,
00201      * ledgers, we don't want expense-type accounts in the menu.
00202      * For BILL, etc. then leave out the income types.
00203      */
00204     switch (ledger->type)
00205     {
00206     case GNCENTRY_ORDER_ENTRY:
00207     case GNCENTRY_ORDER_VIEWER:
00208     case GNCENTRY_INVOICE_ENTRY:
00209     case GNCENTRY_INVOICE_VIEWER:
00210     case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
00211     case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
00212         qf = gnc_get_shared_account_name_quickfill (root, IKEY,
00213                 skip_expense_acct_cb, NULL);
00214         store = gnc_get_shared_account_name_list_store (root, IKEY,
00215                 skip_expense_acct_cb, NULL);
00216         break;
00217 
00218     case GNCENTRY_BILL_ENTRY:
00219     case GNCENTRY_BILL_VIEWER:
00220     case GNCENTRY_EXPVOUCHER_ENTRY:
00221     case GNCENTRY_EXPVOUCHER_VIEWER:
00222     case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
00223     case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
00224     case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
00225     case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
00226     case GNCENTRY_NUM_REGISTER_TYPES:
00227         qf = gnc_get_shared_account_name_quickfill (root, EKEY,
00228                 skip_income_acct_cb, NULL);
00229         store = gnc_get_shared_account_name_list_store (root, EKEY,
00230                 skip_income_acct_cb, NULL);
00231         break;
00232     }
00233 
00234     cell = (ComboCell *)
00235            gnc_table_layout_get_cell (ledger->table->layout, ENTRY_IACCT_CELL);
00236     gnc_combo_cell_use_quickfill_cache (cell, qf);
00237     gnc_combo_cell_use_list_store_cache (cell, store);
00238 
00239     cell = (ComboCell *)
00240            gnc_table_layout_get_cell (ledger->table->layout, ENTRY_BACCT_CELL);
00241     gnc_combo_cell_use_quickfill_cache (cell, qf);
00242     gnc_combo_cell_use_list_store_cache (cell, store);
00243 }
00244 
00245 /* ===================================================================== */
00246 
00247 static void load_taxtable_type_cells (GncEntryLedger *ledger)
00248 {
00249     GList *list;
00250     ComboCell *cell;
00251 
00252     cell = (ComboCell *)
00253            gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTABLE_CELL);
00254     gnc_combo_cell_clear_menu (cell);
00255 
00256     list = gncTaxTableGetTables (ledger->book);
00257     for ( ; list ; list = list->next )
00258     {
00259         GncTaxTable *table = list->data;
00260         const char *name = gncTaxTableGetName (table);
00261         if (name != NULL)
00262             gnc_combo_cell_add_menu_item (cell, (char*)name);
00263     }
00264 }
00265 
00266 static void
00267 gnc_entry_ledger_show_entry (GncEntryLedger *ledger,
00268                              VirtualCellLocation start_loc)
00269 {
00270     VirtualCellLocation end_loc;
00271     int v_row;
00272 
00273     end_loc = start_loc;
00274     v_row = end_loc.virt_row + 1;
00275     end_loc.virt_row = MIN (v_row, ledger->table->num_virt_rows - 1);
00276 
00277     gnc_table_show_range (ledger->table, start_loc, end_loc);
00278 }
00279 
00280 #define DESC_QF_KEY_INVOICES "ENTRY_DESC_CELL_QF_INVOICES"
00281 #define DESC_QF_KEY_BILLS "ENTRY_DESC_CELL_QF_BILLS"
00282 
00283 static void
00284 load_description_cell (GncEntryLedger *ledger)
00285 {
00286     QuickFill *shared_quickfill;
00287     QuickFillCell *cell;
00288 
00289     switch (ledger->type)
00290     {
00291     case GNCENTRY_INVOICE_ENTRY:
00292     case GNCENTRY_INVOICE_VIEWER:
00293     case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
00294     case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
00295         shared_quickfill = gnc_get_shared_entry_desc_quickfill(ledger->book, DESC_QF_KEY_INVOICES, TRUE);
00296         break;
00297     default:
00298         shared_quickfill = gnc_get_shared_entry_desc_quickfill(ledger->book, DESC_QF_KEY_BILLS, FALSE);
00299     };
00300 
00301     cell = (QuickFillCell *)
00302            gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DESC_CELL);
00303     gnc_quickfill_cell_use_quickfill_cache (cell, shared_quickfill);
00304 }
00305 
00306 void gnc_entry_ledger_load_xfer_cells (GncEntryLedger *ledger)
00307 {
00308     load_xfer_type_cells (ledger);
00309     load_taxtable_type_cells (ledger);
00310     load_payment_type_cells (ledger);
00311     load_description_cell (ledger);
00312 }
00313 
00314 /* XXX (FIXME): This should be in a config file! */
00315 /* Copy GncEntry information from the list to the rows of the Ledger. */
00316 /* XXX This code is a cut-n-paste job from the SplitRegister code;
00317  * the split-register should be generalized to the point where a cut-n-paste
00318  * like this isn't required, and this should be trashed.
00319  */
00320 void gnc_entry_ledger_load (GncEntryLedger *ledger, GList *entry_list)
00321 {
00322     GncEntry *blank_entry, *find_entry;
00323     CursorBuffer *cursor_buffer;
00324     Table *table;
00325 
00326     GList *node;
00327     CellBlock *cursor_header, *cursor;
00328     VirtualCellLocation vcell_loc;
00329     VirtualLocation save_loc;
00330     time_t present;
00331     gboolean start_primary_color = TRUE;
00332 
00333     int new_entry_row = -1;
00334 
00335     if (!ledger) return;
00336 
00337     /* Load up cells */
00338     load_discount_type_cells (ledger);
00339     load_discount_how_cells (ledger);
00340     gnc_entry_ledger_load_xfer_cells (ledger);
00341 
00342     blank_entry = gnc_entry_ledger_get_blank_entry (ledger);
00343 
00344     if (blank_entry == NULL && ledger->invoice == NULL && entry_list == NULL)
00345         return;
00346 
00347     if (blank_entry == NULL && ledger->invoice)
00348     {
00349         switch (ledger->type)
00350         {
00351         case GNCENTRY_ORDER_ENTRY:
00352         case GNCENTRY_INVOICE_ENTRY:
00353         case GNCENTRY_BILL_ENTRY:
00354         case GNCENTRY_EXPVOUCHER_ENTRY:
00355         case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
00356         case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
00357         case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
00358 
00359             gnc_suspend_gui_refresh ();
00360 
00361             blank_entry = gncEntryCreate (ledger->book);
00362             gncEntrySetDateGDate (blank_entry, &ledger->last_date_entered);
00363             ledger->blank_entry_guid = *gncEntryGetGUID (blank_entry);
00364 
00365             gnc_resume_gui_refresh ();
00366 
00367             /* The rest of this does not apply to expense vouchers */
00368             if (ledger->type != GNCENTRY_EXPVOUCHER_ENTRY)
00369             {
00370                 const GncOwner *owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
00371                 GncTaxTable *table = NULL;
00372                 GncTaxIncluded taxincluded_p = GNC_TAXINCLUDED_USEGLOBAL;
00373                 gboolean taxincluded = FALSE;
00374                 gnc_numeric discount = gnc_numeric_zero ();
00375                 GNCOptionDB *odb;
00376 
00377                 /* Determine the TaxIncluded and Discount values */
00378                 switch (gncOwnerGetType (owner))
00379                 {
00380                 case GNC_OWNER_CUSTOMER:
00381                     taxincluded_p = gncCustomerGetTaxIncluded (owner->owner.customer);
00382                     discount = gncCustomerGetDiscount (owner->owner.customer);
00383                     break;
00384                 case GNC_OWNER_VENDOR:
00385                     taxincluded_p = gncVendorGetTaxIncluded (owner->owner.vendor);
00386                     break;
00387                 default:
00388                     break;
00389                 }
00390 
00391                 /* Compute the default taxincluded */
00392                 switch (taxincluded_p)
00393                 {
00394                 case GNC_TAXINCLUDED_YES:
00395                     taxincluded = TRUE;
00396                     break;
00397                 case GNC_TAXINCLUDED_NO:
00398                     taxincluded = FALSE;
00399                     break;
00400                 case GNC_TAXINCLUDED_USEGLOBAL:
00401                     if (ledger->gconf_section)
00402                     {
00403                         taxincluded = gnc_gconf_get_bool(ledger->gconf_section, "tax_included", NULL);
00404                     }
00405                     else
00406                     {
00407                         taxincluded = FALSE;
00408                     }
00409                     break;
00410                 }
00411 
00412                 /* Compute the proper taxtable */
00413                 odb = gnc_option_db_new_for_type (GNC_ID_BOOK);
00414                 gnc_option_db_load_from_kvp (odb, qof_book_get_slots (ledger->book));
00415 
00416                 switch (gncOwnerGetType (owner))
00417                 {
00418                 case GNC_OWNER_CUSTOMER:
00419                     table = gnc_option_db_lookup_taxtable_option (odb,
00420                             "Business",
00421                             "Default Customer TaxTable",
00422                             NULL);
00423 
00424                     if (gncCustomerGetTaxTableOverride (owner->owner.customer))
00425                         table = gncCustomerGetTaxTable (owner->owner.customer);
00426                     break;
00427 
00428                 case GNC_OWNER_VENDOR:
00429                     table = gnc_option_db_lookup_taxtable_option (odb,
00430                             "Business",
00431                             "Default Vendor TaxTable",
00432                             NULL);
00433 
00434                     if (gncVendorGetTaxTableOverride (owner->owner.vendor))
00435                         table = gncVendorGetTaxTable (owner->owner.vendor);
00436                     break;
00437 
00438                 default:
00439                     break;
00440                 }
00441 
00442                 gnc_option_db_destroy (odb);
00443 
00444                 if (ledger->is_cust_doc)
00445                 {
00446                     gncEntrySetInvTaxTable (blank_entry, table);
00447                     gncEntrySetInvTaxIncluded (blank_entry, taxincluded);
00448                     gncEntrySetInvDiscount (blank_entry, discount);
00449                 }
00450                 else
00451                 {
00452                     gncEntrySetBillTaxTable (blank_entry, table);
00453                     gncEntrySetBillTaxIncluded (blank_entry, taxincluded);
00454                 }
00455             }
00456 
00457             break;
00458         default:
00459             ledger->blank_entry_guid = *guid_null ();
00460             break;
00461         }
00462         ledger->blank_entry_edited = FALSE;
00463     }
00464 
00465     table = ledger->table;
00466 
00467     gnc_table_leave_update (table, table->current_cursor_loc);
00468     save_loc = table->current_cursor_loc;
00469 
00470     /* Figure out where we are going to */
00471     if (ledger->traverse_to_new)
00472     {
00473         find_entry = blank_entry;
00474     }
00475     else if (ledger->hint_entry)
00476     {
00477         find_entry = ledger->hint_entry;
00478     }
00479     else
00480     {
00481         find_entry = gnc_entry_ledger_get_current_entry(ledger);
00482         /* XXX: get current entry (cursor_hint_xxx) */
00483     }
00484 
00485     /* If the current cursor has changed we save the values for later
00486      * possible restoration. */
00487     if (gnc_table_current_cursor_changed (table, TRUE) &&
00488             (find_entry == gnc_entry_ledger_get_current_entry (ledger)))
00489     {
00490         cursor_buffer = gnc_cursor_buffer_new ();
00491         gnc_table_save_current_cursor (table, cursor_buffer);
00492     }
00493     else
00494         cursor_buffer = NULL;
00495 
00496     /* disable move callback -- we don't want the cascade of
00497      * callbacks while we are fiddling with loading the register */
00498     gnc_table_control_allow_move (table->control, FALSE);
00499 
00500     /* invalidate the cursor */
00501     {
00502         VirtualLocation virt_loc;
00503 
00504         virt_loc.vcell_loc.virt_row = -1;
00505         virt_loc.vcell_loc.virt_col = -1;
00506         virt_loc.phys_row_offset = -1;
00507         virt_loc.phys_col_offset = -1;
00508 
00509         gnc_table_move_cursor_gui (table, virt_loc);
00510     }
00511 
00512     /* make sure that the header is loaded */
00513     vcell_loc.virt_row = 0;
00514     vcell_loc.virt_col = 0;
00515     cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
00516     gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
00517     vcell_loc.virt_row++;
00518 
00519     /* get the current time and reset the dividing row */
00520     present = gnc_timet_get_today_end ();
00521     table->model->dividing_row_upper = -1;
00522     table->model->dividing_row = -1;
00523     cursor = gnc_table_layout_get_cursor (table->layout, "cursor");
00524 
00525     /* Populate the table */
00526     for (node = entry_list; node; node = node->next)
00527     {
00528         GncEntry *entry = node->data;
00529 
00530         /* Don't load the blank entry */
00531         if (entry == blank_entry)
00532             continue;
00533 
00534         /* If this is the first load of the ledger, fill the quickfill cells */
00535         {
00536             /* XXX */
00537         }
00538 
00539         if (entry == find_entry)
00540             new_entry_row = vcell_loc.virt_row;
00541 
00542         gnc_table_set_vcell (table, cursor, gncEntryGetGUID (entry),
00543                              TRUE, start_primary_color, vcell_loc);
00544         vcell_loc.virt_row++;
00545 
00546         /* Flip color for the next guy */
00547         start_primary_color = !start_primary_color;
00548     }
00549 
00550     /* Add the blank entry at the end. */
00551     if (blank_entry)
00552     {
00553         gnc_table_set_vcell (table, cursor, gncEntryGetGUID (blank_entry),
00554                              TRUE, start_primary_color, vcell_loc);
00555 
00556         if (find_entry == blank_entry)
00557             new_entry_row = vcell_loc.virt_row;
00558 
00559         vcell_loc.virt_row++;
00560     }
00561 
00562     /* Resize the table */
00563     gnc_table_set_size (table, vcell_loc.virt_row, 1);
00564 
00565     /* Restore the cursor to its rightful position */
00566     if (new_entry_row > 0)
00567         save_loc.vcell_loc.virt_row = new_entry_row;
00568 
00569     if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
00570     {
00571         gnc_table_move_cursor_gui (table, save_loc);
00572 
00573         if (find_entry == gnc_entry_ledger_get_current_entry (ledger))
00574             gnc_table_restore_current_cursor (table, cursor_buffer);
00575     }
00576 
00577     gnc_cursor_buffer_destroy (cursor_buffer);
00578     cursor_buffer = NULL;
00579 
00580     /* Reset the ledger */
00581     ledger->traverse_to_new = FALSE;
00582     ledger->hint_entry = NULL;
00583 
00584     /* Set the cell fractions */
00585 
00586 
00587     gnc_table_refresh_gui (table, TRUE);
00588     gnc_entry_ledger_show_entry (ledger, table->current_cursor_loc.vcell_loc);
00589 
00590     /* Set completion character */
00591     gnc_combo_cell_set_complete_char
00592     ((ComboCell *)
00593      gnc_table_layout_get_cell (table->layout, ENTRY_IACCT_CELL),
00594      gnc_get_account_separator ());
00595 
00596     gnc_combo_cell_set_complete_char
00597     ((ComboCell *)
00598      gnc_table_layout_get_cell (table->layout, ENTRY_BACCT_CELL),
00599      gnc_get_account_separator ());
00600 
00601     /* enable callback for cursor user-driven moves */
00602     gnc_table_control_allow_move (table->control, TRUE);
00603 }
00604 
00605 /* =========================== END OF FILE ========================== */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines