gnucash/gnucash/register/ledger-core/gncEntryLedgerLoad.c
John Ralls fcc1653822 Replace overly indirect gnc_business_get_default_tax_table.
With gncTaxTableGetDefault.

qof_book_get_default_tax_table would have been even better but it
would have created a circular dependency between QofBook and
GncTaxTable.
2019-08-22 12:30:33 -07:00

616 lines
19 KiB
C

/*
* gncEntryLedgerLoad.c -- a Ledger widget for entering GncEntry objects
* Copyright (C) 2001, 2002, 2003 Derek Atkins
* Author: Derek Atkins <warlord@MIT.EDU>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact:
*
* Free Software Foundation Voice: +1-617-542-5942
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
* Boston, MA 02110-1301, USA gnu@gnu.org
*/
#include <config.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "Account.h"
#include "account-quickfill.h"
#include "combocell.h"
#include "gnc-component-manager.h"
#include "gnc-prefs.h"
#include "gnc-ui-util.h"
#include "recncell.h"
#include "gncEntry.h"
#include "gncEntryLedger.h"
#include "gncEntryLedgerP.h"
#include "quickfillcell.h"
#include "gnc-entry-quickfill.h"
#define GNC_PREF_TAX_INCL "tax-included"
static const QofLogModule log_module = "Business Entry Ledger";
/* XXX: This should go elsewhere */
const char * gnc_entry_ledger_type_string_getter (char flag)
{
switch (flag)
{
case '1':
return _("$");
case '2':
return _("%");
default:
break;
};
return "?";
}
const char * gnc_entry_ledger_how_string_getter (char flag)
{
switch (flag)
{
case '1':
return _("<");
case '2':
return _("=");
case '3':
return _(">");
default:
break;
};
return "?";
}
static void load_discount_type_cells (GncEntryLedger *ledger)
{
RecnCell *cell;
if (!ledger) return;
cell = (RecnCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISTYPE_CELL);
if (!cell) return;
gnc_recn_cell_set_valid_flags (cell, "12", '2');
gnc_recn_cell_set_flag_order (cell, "21");
gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_type_string_getter);
}
static void load_discount_how_cells (GncEntryLedger *ledger)
{
RecnCell *cell;
if (!ledger) return;
cell = (RecnCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISHOW_CELL);
if (!cell) return;
gnc_recn_cell_set_valid_flags (cell, "123", '1');
gnc_recn_cell_set_flag_order (cell, "123");
gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_how_string_getter);
}
static void load_payment_type_cells (GncEntryLedger *ledger)
{
ComboCell *cell;
const GncOwner *owner;
GncEmployee *employee;
cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
ENTRY_PAYMENT_CELL);
if (!cell) return;
if (!ledger->invoice) return;
owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
if (gncOwnerGetType (owner) != GNC_OWNER_EMPLOYEE)
return;
employee = gncOwnerGetEmployee (owner);
g_return_if_fail (employee);
gnc_combo_cell_clear_menu (cell);
gnc_combo_cell_add_menu_item (cell, _("Cash"));
if (gncEmployeeGetCCard (employee))
gnc_combo_cell_add_menu_item (cell, _("Charge"));
}
/* ==================================================================== */
/* Return TRUE if we don't want to add this account to the xfer menu */
static gboolean
skip_expense_acct_cb (Account *account, gpointer user_data)
{
GNCAccountType type;
/* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
type = xaccAccountGetType (account);
if (type == ACCT_TYPE_PAYABLE || type == ACCT_TYPE_RECEIVABLE ||
type == ACCT_TYPE_CASH || type == ACCT_TYPE_BANK ||
type == ACCT_TYPE_EQUITY || type == ACCT_TYPE_TRADING)
{
return TRUE;
}
/* If this is an ORDER or INVOICE, then leave out the expenses. */
if (type == ACCT_TYPE_EXPENSE) return TRUE;
/* Don't add placeholder accounts */
if (xaccAccountGetPlaceholder (account)) return TRUE;
return FALSE;
}
static gboolean
skip_income_acct_cb (Account *account, gpointer user_data)
{
GNCAccountType type;
/* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
type = xaccAccountGetType (account);
if (type == ACCT_TYPE_PAYABLE || type == ACCT_TYPE_RECEIVABLE ||
type == ACCT_TYPE_CASH || type == ACCT_TYPE_BANK ||
type == ACCT_TYPE_EQUITY || type == ACCT_TYPE_TRADING)
{
return TRUE;
}
/* If this is a BILL, then leave out the incomes */
if (type == ACCT_TYPE_INCOME) return TRUE;
/* Don't add placeholder accounts */
if (xaccAccountGetPlaceholder (account)) return TRUE;
return FALSE;
}
/* ===================================================================== */
/* Splat the account name into the transfer cell combobox menu */
#define EKEY "Expense Business entry quickfill"
#define IKEY "Income Business entry quickfill"
static void
load_xfer_type_cells (GncEntryLedger *ledger)
{
Account *root;
ComboCell *cell;
QuickFill *qf = NULL;
GtkListStore *store = NULL;
root = gnc_book_get_root_account (ledger->book);
if (root == NULL) return;
/* Use a common, shared quickfill. For the ORDER or INVOICE,
* ledgers, we don't want expense-type accounts in the menu.
* For BILL, etc. then leave out the income types.
*/
switch (ledger->type)
{
case GNCENTRY_ORDER_ENTRY:
case GNCENTRY_ORDER_VIEWER:
case GNCENTRY_INVOICE_ENTRY:
case GNCENTRY_INVOICE_VIEWER:
case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
qf = gnc_get_shared_account_name_quickfill (root, IKEY,
skip_expense_acct_cb, NULL);
store = gnc_get_shared_account_name_list_store (root, IKEY,
skip_expense_acct_cb, NULL);
break;
case GNCENTRY_BILL_ENTRY:
case GNCENTRY_BILL_VIEWER:
case GNCENTRY_EXPVOUCHER_ENTRY:
case GNCENTRY_EXPVOUCHER_VIEWER:
case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
case GNCENTRY_NUM_REGISTER_TYPES:
qf = gnc_get_shared_account_name_quickfill (root, EKEY,
skip_income_acct_cb, NULL);
store = gnc_get_shared_account_name_list_store (root, EKEY,
skip_income_acct_cb, NULL);
break;
default:
PWARN ("Bad GncEntryLedgerType");
break;
}
cell = (ComboCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_IACCT_CELL);
gnc_combo_cell_use_quickfill_cache (cell, qf);
gnc_combo_cell_use_list_store_cache (cell, store);
cell = (ComboCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_BACCT_CELL);
gnc_combo_cell_use_quickfill_cache (cell, qf);
gnc_combo_cell_use_list_store_cache (cell, store);
}
/* ===================================================================== */
static void load_taxtable_type_cells (GncEntryLedger *ledger)
{
GList *list;
ComboCell *cell;
cell = (ComboCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTABLE_CELL);
gnc_combo_cell_clear_menu (cell);
list = gncTaxTableGetTables (ledger->book);
for ( ; list ; list = list->next )
{
GncTaxTable *table = list->data;
const char *name = gncTaxTableGetName (table);
if (name != NULL)
gnc_combo_cell_add_menu_item (cell, (char*)name);
}
}
static void
gnc_entry_ledger_show_entry (GncEntryLedger *ledger,
VirtualCellLocation start_loc)
{
VirtualCellLocation end_loc;
int v_row;
end_loc = start_loc;
v_row = end_loc.virt_row + 1;
end_loc.virt_row = MIN (v_row, ledger->table->num_virt_rows - 1);
gnc_table_show_range (ledger->table, start_loc, end_loc);
}
#define DESC_QF_KEY_INVOICES "ENTRY_DESC_CELL_QF_INVOICES"
#define DESC_QF_KEY_BILLS "ENTRY_DESC_CELL_QF_BILLS"
static void
load_description_cell (GncEntryLedger *ledger)
{
QuickFill *shared_quickfill;
QuickFillCell *cell;
switch (ledger->type)
{
case GNCENTRY_INVOICE_ENTRY:
case GNCENTRY_INVOICE_VIEWER:
case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
shared_quickfill = gnc_get_shared_entry_desc_quickfill(ledger->book, DESC_QF_KEY_INVOICES, TRUE);
break;
default:
shared_quickfill = gnc_get_shared_entry_desc_quickfill(ledger->book, DESC_QF_KEY_BILLS, FALSE);
break;
};
cell = (QuickFillCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DESC_CELL);
gnc_quickfill_cell_use_quickfill_cache (cell, shared_quickfill);
}
void gnc_entry_ledger_load_xfer_cells (GncEntryLedger *ledger)
{
load_xfer_type_cells (ledger);
load_taxtable_type_cells (ledger);
load_payment_type_cells (ledger);
load_description_cell (ledger);
}
/* XXX (FIXME): This should be in a config file! */
/* Copy GncEntry information from the list to the rows of the Ledger. */
/* XXX This code is a cut-n-paste job from the SplitRegister code;
* the split-register should be generalized to the point where a cut-n-paste
* like this isn't required, and this should be trashed.
*/
void gnc_entry_ledger_load (GncEntryLedger *ledger, GList *entry_list)
{
GncEntry *blank_entry, *find_entry;
CursorBuffer *cursor_buffer;
Table *table;
GList *node;
CellBlock *cursor_header, *cursor;
VirtualCellLocation vcell_loc;
VirtualLocation save_loc;
gboolean start_primary_color = TRUE;
int new_entry_row = -1;
if (!ledger) return;
/* Load up cells */
load_discount_type_cells (ledger);
load_discount_how_cells (ledger);
gnc_entry_ledger_load_xfer_cells (ledger);
blank_entry = gnc_entry_ledger_get_blank_entry (ledger);
if (blank_entry == NULL && ledger->invoice == NULL && entry_list == NULL)
return;
if (blank_entry == NULL && ledger->invoice)
{
switch (ledger->type)
{
case GNCENTRY_ORDER_ENTRY:
case GNCENTRY_INVOICE_ENTRY:
case GNCENTRY_BILL_ENTRY:
case GNCENTRY_EXPVOUCHER_ENTRY:
case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
gnc_suspend_gui_refresh ();
blank_entry = gncEntryCreate (ledger->book);
gncEntrySetDateGDate (blank_entry, &ledger->last_date_entered);
ledger->blank_entry_guid = *gncEntryGetGUID (blank_entry);
gnc_resume_gui_refresh ();
/* The rest of this does not apply to expense vouchers */
if (ledger->type != GNCENTRY_EXPVOUCHER_ENTRY)
{
const GncOwner *owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
GncTaxTable *table = NULL;
GncTaxIncluded taxincluded_p = GNC_TAXINCLUDED_USEGLOBAL;
gboolean taxincluded = FALSE;
gnc_numeric discount = gnc_numeric_zero ();
gnc_numeric price = gnc_numeric_zero ();
/* Determine the Price from Customer's or Vendor's Job */
switch (gncOwnerGetType (gncInvoiceGetOwner (ledger->invoice)))
{
case GNC_OWNER_JOB:
price = gncJobGetRate( gncOwnerGetJob (gncInvoiceGetOwner (ledger->invoice)));
break;
default:
break;
}
/* Determine the TaxIncluded and Discount values */
switch (gncOwnerGetType (owner))
{
case GNC_OWNER_CUSTOMER:
taxincluded_p = gncCustomerGetTaxIncluded (owner->owner.customer);
discount = gncCustomerGetDiscount (owner->owner.customer);
break;
case GNC_OWNER_VENDOR:
taxincluded_p = gncVendorGetTaxIncluded (owner->owner.vendor);
break;
default:
break;
}
/* Compute the default taxincluded */
switch (taxincluded_p)
{
case GNC_TAXINCLUDED_YES:
taxincluded = TRUE;
break;
case GNC_TAXINCLUDED_NO:
taxincluded = FALSE;
break;
case GNC_TAXINCLUDED_USEGLOBAL:
if (ledger->prefs_group)
{
taxincluded = gnc_prefs_get_bool (ledger->prefs_group, GNC_PREF_TAX_INCL);
}
else
{
taxincluded = FALSE;
}
break;
}
/* Compute the proper taxtable */
switch (gncOwnerGetType (owner))
{
case GNC_OWNER_CUSTOMER:
table = gncTaxTableGetDefault (ledger->book,
GNC_OWNER_CUSTOMER);
if (gncCustomerGetTaxTableOverride (owner->owner.customer))
table = gncCustomerGetTaxTable (owner->owner.customer);
break;
case GNC_OWNER_VENDOR:
table = gncTaxTableGetDefault (ledger->book,
GNC_OWNER_VENDOR);
if (gncVendorGetTaxTableOverride (owner->owner.vendor))
table = gncVendorGetTaxTable (owner->owner.vendor);
break;
default:
break;
}
if (ledger->is_cust_doc)
{
gncEntrySetInvTaxable (blank_entry, table != NULL);
gncEntrySetInvTaxTable (blank_entry, table);
gncEntrySetInvTaxIncluded (blank_entry, taxincluded);
gncEntrySetInvDiscount (blank_entry, discount);
gncEntrySetInvPrice (blank_entry, price);
}
else
{
gncEntrySetBillTaxable (blank_entry, table != NULL);
gncEntrySetBillTaxTable (blank_entry, table);
gncEntrySetBillTaxIncluded (blank_entry, taxincluded);
gncEntrySetBillPrice (blank_entry, price);
}
}
break;
default:
ledger->blank_entry_guid = *guid_null ();
break;
}
ledger->blank_entry_edited = FALSE;
}
table = ledger->table;
gnc_table_leave_update (table, table->current_cursor_loc);
save_loc = table->current_cursor_loc;
/* Figure out where we are going to */
if (ledger->traverse_to_new)
{
find_entry = blank_entry;
}
else if (ledger->hint_entry)
{
find_entry = ledger->hint_entry;
}
else
{
find_entry = gnc_entry_ledger_get_current_entry(ledger);
/* XXX: get current entry (cursor_hint_xxx) */
}
/* If the current cursor has changed we save the values for later
* possible restoration. */
if (gnc_table_current_cursor_changed (table, TRUE) &&
(find_entry == gnc_entry_ledger_get_current_entry (ledger)))
{
cursor_buffer = gnc_cursor_buffer_new ();
gnc_table_save_current_cursor (table, cursor_buffer);
}
else
cursor_buffer = NULL;
/* disable move callback -- we don't want the cascade of
* callbacks while we are fiddling with loading the register */
gnc_table_control_allow_move (table->control, FALSE);
/* invalidate the cursor */
{
VirtualLocation virt_loc;
virt_loc.vcell_loc.virt_row = -1;
virt_loc.vcell_loc.virt_col = -1;
virt_loc.phys_row_offset = -1;
virt_loc.phys_col_offset = -1;
gnc_table_move_cursor_gui (table, virt_loc);
}
/* make sure that the header is loaded */
vcell_loc.virt_row = 0;
vcell_loc.virt_col = 0;
cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
vcell_loc.virt_row++;
/* get the current time and reset the dividing row */
table->model->dividing_row_upper = -1;
table->model->dividing_row = -1;
table->model->dividing_row_lower = -1;
cursor = gnc_table_layout_get_cursor (table->layout, "cursor");
/* Populate the table */
for (node = entry_list; node; node = node->next)
{
GncEntry *entry = node->data;
/* Don't load the blank entry */
if (entry == blank_entry)
continue;
/* If this is the first load of the ledger, fill the quickfill cells */
{
/* XXX */
}
if (entry == find_entry)
new_entry_row = vcell_loc.virt_row;
gnc_table_set_vcell (table, cursor, gncEntryGetGUID (entry),
TRUE, start_primary_color, vcell_loc);
vcell_loc.virt_row++;
/* Flip color for the next guy */
start_primary_color = !start_primary_color;
}
/* Add the blank entry at the end. */
if (blank_entry)
{
gnc_table_set_vcell (table, cursor, gncEntryGetGUID (blank_entry),
TRUE, start_primary_color, vcell_loc);
if (find_entry == blank_entry)
new_entry_row = vcell_loc.virt_row;
vcell_loc.virt_row++;
}
/* Resize the table */
gnc_table_set_size (table, vcell_loc.virt_row, 1);
/* Restore the cursor to its rightful position */
if (new_entry_row > 0)
save_loc.vcell_loc.virt_row = new_entry_row;
if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
{
gnc_table_move_cursor_gui (table, save_loc);
if (find_entry == gnc_entry_ledger_get_current_entry (ledger))
gnc_table_restore_current_cursor (table, cursor_buffer);
}
gnc_cursor_buffer_destroy (cursor_buffer);
cursor_buffer = NULL;
/* Reset the ledger */
ledger->traverse_to_new = FALSE;
ledger->hint_entry = NULL;
/* Set the cell fractions */
gnc_table_refresh_gui (table, TRUE);
gnc_entry_ledger_show_entry (ledger, table->current_cursor_loc.vcell_loc);
/* Set completion character */
gnc_combo_cell_set_complete_char
((ComboCell *)
gnc_table_layout_get_cell (table->layout, ENTRY_IACCT_CELL),
gnc_get_account_separator ());
gnc_combo_cell_set_complete_char
((ComboCell *)
gnc_table_layout_get_cell (table->layout, ENTRY_BACCT_CELL),
gnc_get_account_separator ());
/* enable callback for cursor user-driven moves */
gnc_table_control_allow_move (table->control, TRUE);
}
/* =========================== END OF FILE ========================== */