GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gncEntryLedgerLoad.c
1 /*
2  * gncEntryLedgerLoad.c -- a Ledger widget for entering GncEntry objects
3  * Copyright (C) 2001, 2002, 2003 Derek Atkins
4  * Author: Derek Atkins <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, contact:
18  *
19  * Free Software Foundation Voice: +1-617-542-5942
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
21  * Boston, MA 02110-1301, USA [email protected]
22  */
23 
24 #include "config.h"
25 
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 
29 #include "Account.h"
30 #include "account-quickfill.h"
31 #include "combocell.h"
32 #include "gnc-component-manager.h"
33 #include "gnc-prefs.h"
34 #include "gnc-ui-util.h"
35 #include "recncell.h"
36 
37 #include "business-helpers.h"
38 
39 #include "gncEntry.h"
40 #include "gncEntryLedger.h"
41 #include "gncEntryLedgerP.h"
42 #include "quickfillcell.h"
43 #include "app-utils/gnc-entry-quickfill.h"
44 
45 #define GNC_PREF_TAX_INCL "tax-included"
46 
47 static const QofLogModule log_module = "Business Entry Ledger";
48 
49 /* XXX: This should go elsewhere */
50 const char * gnc_entry_ledger_type_string_getter (char flag)
51 {
52  switch (flag)
53  {
54  case '1':
55  return _("$");
56  case '2':
57  return _("%");
58  default:
59  break;
60  };
61  return "?";
62 }
63 
64 const char * gnc_entry_ledger_how_string_getter (char flag)
65 {
66  switch (flag)
67  {
68  case '1':
69  return _("<");
70  case '2':
71  return _("=");
72  case '3':
73  return _(">");
74  default:
75  break;
76  };
77  return "?";
78 }
79 
80 static void load_discount_type_cells (GncEntryLedger *ledger)
81 {
82  RecnCell *cell;
83 
84  if (!ledger) return;
85 
86  cell = (RecnCell *)
87  gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISTYPE_CELL);
88 
89  if (!cell) return;
90 
91  gnc_recn_cell_set_valid_flags (cell, "12", '2');
92  gnc_recn_cell_set_flag_order (cell, "21");
93  gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_type_string_getter);
94 }
95 
96 static void load_discount_how_cells (GncEntryLedger *ledger)
97 {
98  RecnCell *cell;
99 
100  if (!ledger) return;
101 
102  cell = (RecnCell *)
103  gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISHOW_CELL);
104 
105  if (!cell) return;
106 
107  gnc_recn_cell_set_valid_flags (cell, "123", '1');
108  gnc_recn_cell_set_flag_order (cell, "123");
109  gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_how_string_getter);
110 }
111 
112 static void load_payment_type_cells (GncEntryLedger *ledger)
113 {
114  ComboCell *cell;
115  const GncOwner *owner;
116  GncEmployee *employee;
117 
118  cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
119  ENTRY_PAYMENT_CELL);
120  if (!cell) return;
121 
122  if (!ledger->invoice) return;
123 
124  owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
125  if (gncOwnerGetType (owner) != GNC_OWNER_EMPLOYEE)
126  return;
127 
128  employee = gncOwnerGetEmployee (owner);
129  g_return_if_fail (employee);
130 
131  gnc_combo_cell_clear_menu (cell);
132  gnc_combo_cell_add_menu_item (cell, _("Cash"));
133 
134  if (gncEmployeeGetCCard (employee))
135  gnc_combo_cell_add_menu_item (cell, _("Charge"));
136 }
137 
138 /* ==================================================================== */
139 /* Return TRUE if we don't want to add this account to the xfer menu */
140 
141 static gboolean
142 skip_expense_acct_cb (Account *account, gpointer user_data)
143 {
144  GNCAccountType type;
145 
146  /* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
147  type = xaccAccountGetType (account);
148  if (type == ACCT_TYPE_PAYABLE || type == ACCT_TYPE_RECEIVABLE ||
149  type == ACCT_TYPE_CASH || type == ACCT_TYPE_BANK ||
150  type == ACCT_TYPE_EQUITY || type == ACCT_TYPE_TRADING)
151  {
152  return TRUE;
153  }
154 
155  /* If this is an ORDER or INVOICE, then leave out the expenses. */
156  if (type == ACCT_TYPE_EXPENSE) return TRUE;
157 
158  /* Don't add placeholder accounts */
159  if (xaccAccountGetPlaceholder (account)) return TRUE;
160 
161  return FALSE;
162 }
163 
164 static gboolean
165 skip_income_acct_cb (Account *account, gpointer user_data)
166 {
167  GNCAccountType type;
168 
169  /* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
170  type = xaccAccountGetType (account);
171  if (type == ACCT_TYPE_PAYABLE || type == ACCT_TYPE_RECEIVABLE ||
172  type == ACCT_TYPE_CASH || type == ACCT_TYPE_BANK ||
173  type == ACCT_TYPE_EQUITY || type == ACCT_TYPE_TRADING)
174  {
175  return TRUE;
176  }
177 
178  /* If this is a BILL, then leave out the incomes */
179  if (type == ACCT_TYPE_INCOME) return TRUE;
180 
181  /* Don't add placeholder accounts */
182  if (xaccAccountGetPlaceholder (account)) return TRUE;
183 
184  return FALSE;
185 }
186 
187 /* ===================================================================== */
188 /* Splat the account name into the transfer cell combobox menu */
189 
190 #define EKEY "Expense Business entry quickfill"
191 #define IKEY "Income Business entry quickfill"
192 
193 static void
194 load_xfer_type_cells (GncEntryLedger *ledger)
195 {
196  Account *root;
197  ComboCell *cell;
198  QuickFill *qf = NULL;
199  GtkListStore *store = NULL;
200 
201  root = gnc_book_get_root_account (ledger->book);
202  if (root == NULL) return;
203 
204  /* Use a common, shared quickfill. For the ORDER or INVOICE,
205  * ledgers, we don't want expense-type accounts in the menu.
206  * For BILL, etc. then leave out the income types.
207  */
208  switch (ledger->type)
209  {
210  case GNCENTRY_ORDER_ENTRY:
211  case GNCENTRY_ORDER_VIEWER:
212  case GNCENTRY_INVOICE_ENTRY:
213  case GNCENTRY_INVOICE_VIEWER:
214  case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
215  case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
216  qf = gnc_get_shared_account_name_quickfill (root, IKEY,
217  skip_expense_acct_cb, NULL);
218  store = gnc_get_shared_account_name_list_store (root, IKEY,
219  skip_expense_acct_cb, NULL);
220  break;
221 
222  case GNCENTRY_BILL_ENTRY:
223  case GNCENTRY_BILL_VIEWER:
224  case GNCENTRY_EXPVOUCHER_ENTRY:
225  case GNCENTRY_EXPVOUCHER_VIEWER:
226  case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
227  case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
228  case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
229  case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
230  case GNCENTRY_NUM_REGISTER_TYPES:
231  qf = gnc_get_shared_account_name_quickfill (root, EKEY,
232  skip_income_acct_cb, NULL);
233  store = gnc_get_shared_account_name_list_store (root, EKEY,
234  skip_income_acct_cb, NULL);
235  break;
236  default:
237  PWARN ("Bad GncEntryLedgerType");
238  break;
239  }
240 
241  cell = (ComboCell *)
242  gnc_table_layout_get_cell (ledger->table->layout, ENTRY_IACCT_CELL);
244  gnc_combo_cell_use_list_store_cache (cell, store);
245 
246  cell = (ComboCell *)
247  gnc_table_layout_get_cell (ledger->table->layout, ENTRY_BACCT_CELL);
249  gnc_combo_cell_use_list_store_cache (cell, store);
250 }
251 
252 /* ===================================================================== */
253 
254 static void load_taxtable_type_cells (GncEntryLedger *ledger)
255 {
256  GList *list;
257  ComboCell *cell;
258 
259  cell = (ComboCell *)
260  gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTABLE_CELL);
261  gnc_combo_cell_clear_menu (cell);
262 
263  list = gncTaxTableGetTables (ledger->book);
264  for ( ; list ; list = list->next )
265  {
266  GncTaxTable *table = list->data;
267  const char *name = gncTaxTableGetName (table);
268  if (name != NULL)
269  gnc_combo_cell_add_menu_item (cell, (char*)name);
270  }
271 }
272 
273 static void
274 gnc_entry_ledger_show_entry (GncEntryLedger *ledger,
275  VirtualCellLocation start_loc)
276 {
277  VirtualCellLocation end_loc;
278  int v_row;
279 
280  end_loc = start_loc;
281  v_row = end_loc.virt_row + 1;
282  end_loc.virt_row = MIN (v_row, ledger->table->num_virt_rows - 1);
283 
284  gnc_table_show_range (ledger->table, start_loc, end_loc);
285 }
286 
287 #define DESC_QF_KEY_INVOICES "ENTRY_DESC_CELL_QF_INVOICES"
288 #define DESC_QF_KEY_BILLS "ENTRY_DESC_CELL_QF_BILLS"
289 
290 static void
291 load_description_cell (GncEntryLedger *ledger)
292 {
293  QuickFill *shared_quickfill;
294  QuickFillCell *cell;
295 
296  switch (ledger->type)
297  {
298  case GNCENTRY_INVOICE_ENTRY:
299  case GNCENTRY_INVOICE_VIEWER:
300  case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
301  case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
302  shared_quickfill = gnc_get_shared_entry_desc_quickfill(ledger->book, DESC_QF_KEY_INVOICES, TRUE);
303  break;
304  default:
305  shared_quickfill = gnc_get_shared_entry_desc_quickfill(ledger->book, DESC_QF_KEY_BILLS, FALSE);
306  break;
307  };
308 
309  cell = (QuickFillCell *)
310  gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DESC_CELL);
311  gnc_quickfill_cell_use_quickfill_cache (cell, shared_quickfill);
312 }
313 
314 void gnc_entry_ledger_load_xfer_cells (GncEntryLedger *ledger)
315 {
316  load_xfer_type_cells (ledger);
317  load_taxtable_type_cells (ledger);
318  load_payment_type_cells (ledger);
319  load_description_cell (ledger);
320 }
321 
322 /* XXX (FIXME): This should be in a config file! */
323 /* Copy GncEntry information from the list to the rows of the Ledger. */
324 /* XXX This code is a cut-n-paste job from the SplitRegister code;
325  * the split-register should be generalized to the point where a cut-n-paste
326  * like this isn't required, and this should be trashed.
327  */
328 void gnc_entry_ledger_load (GncEntryLedger *ledger, GList *entry_list)
329 {
330  GncEntry *blank_entry, *find_entry;
331  CursorBuffer *cursor_buffer;
332  Table *table;
333 
334  GList *node;
335  CellBlock *cursor_header, *cursor;
336  VirtualCellLocation vcell_loc;
337  VirtualLocation save_loc;
338  gboolean start_primary_color = TRUE;
339 
340  int new_entry_row = -1;
341 
342  if (!ledger) return;
343 
344  /* Load up cells */
345  load_discount_type_cells (ledger);
346  load_discount_how_cells (ledger);
347  gnc_entry_ledger_load_xfer_cells (ledger);
348 
349  blank_entry = gnc_entry_ledger_get_blank_entry (ledger);
350 
351  if (blank_entry == NULL && ledger->invoice == NULL && entry_list == NULL)
352  return;
353 
354  if (blank_entry == NULL && ledger->invoice)
355  {
356  switch (ledger->type)
357  {
358  case GNCENTRY_ORDER_ENTRY:
359  case GNCENTRY_INVOICE_ENTRY:
360  case GNCENTRY_BILL_ENTRY:
361  case GNCENTRY_EXPVOUCHER_ENTRY:
362  case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
363  case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
364  case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
365 
366  gnc_suspend_gui_refresh ();
367 
368  blank_entry = gncEntryCreate (ledger->book);
369  gncEntrySetDateGDate (blank_entry, &ledger->last_date_entered);
370  ledger->blank_entry_guid = *gncEntryGetGUID (blank_entry);
371 
372  gnc_resume_gui_refresh ();
373 
374  /* The rest of this does not apply to expense vouchers */
375  if (ledger->type != GNCENTRY_EXPVOUCHER_ENTRY)
376  {
377  const GncOwner *owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
378  GncTaxTable *table = NULL;
380  gboolean taxincluded = FALSE;
381  gnc_numeric discount = gnc_numeric_zero ();
382  gnc_numeric price = gnc_numeric_zero ();
383 
384  /* Determine the Price from Customer's or Vendor's Job */
385  switch (gncOwnerGetType (gncInvoiceGetOwner (ledger->invoice)))
386  {
387  case GNC_OWNER_JOB:
388  price = gncJobGetRate( gncOwnerGetJob (gncInvoiceGetOwner (ledger->invoice)));
389  break;
390  default:
391  break;
392  }
393 
394  /* Determine the TaxIncluded and Discount values */
395  switch (gncOwnerGetType (owner))
396  {
397  case GNC_OWNER_CUSTOMER:
398  taxincluded_p = gncCustomerGetTaxIncluded (owner->owner.customer);
399  discount = gncCustomerGetDiscount (owner->owner.customer);
400  break;
401  case GNC_OWNER_VENDOR:
402  taxincluded_p = gncVendorGetTaxIncluded (owner->owner.vendor);
403  break;
404  default:
405  break;
406  }
407 
408  /* Compute the default taxincluded */
409  switch (taxincluded_p)
410  {
411  case GNC_TAXINCLUDED_YES:
412  taxincluded = TRUE;
413  break;
414  case GNC_TAXINCLUDED_NO:
415  taxincluded = FALSE;
416  break;
418  if (ledger->prefs_group)
419  {
420  taxincluded = gnc_prefs_get_bool (ledger->prefs_group, GNC_PREF_TAX_INCL);
421  }
422  else
423  {
424  taxincluded = FALSE;
425  }
426  break;
427  }
428 
429  /* Compute the proper taxtable */
430  switch (gncOwnerGetType (owner))
431  {
432  case GNC_OWNER_CUSTOMER:
433  table = gnc_business_get_default_tax_table (ledger->book,
434  GNC_OWNER_CUSTOMER);
435 
436  if (gncCustomerGetTaxTableOverride (owner->owner.customer))
437  table = gncCustomerGetTaxTable (owner->owner.customer);
438  break;
439 
440  case GNC_OWNER_VENDOR:
441  table = gnc_business_get_default_tax_table (ledger->book,
442  GNC_OWNER_VENDOR);
443 
444  if (gncVendorGetTaxTableOverride (owner->owner.vendor))
445  table = gncVendorGetTaxTable (owner->owner.vendor);
446  break;
447 
448  default:
449  break;
450  }
451 
452  if (ledger->is_cust_doc)
453  {
454  gncEntrySetInvTaxTable (blank_entry, table);
455  gncEntrySetInvTaxIncluded (blank_entry, taxincluded);
456  gncEntrySetInvDiscount (blank_entry, discount);
457  gncEntrySetInvPrice (blank_entry, price);
458  }
459  else
460  {
461  gncEntrySetBillTaxTable (blank_entry, table);
462  gncEntrySetBillTaxIncluded (blank_entry, taxincluded);
463  gncEntrySetBillPrice (blank_entry, price);
464  }
465  }
466 
467  break;
468  default:
469  ledger->blank_entry_guid = *guid_null ();
470  break;
471  }
472  ledger->blank_entry_edited = FALSE;
473  }
474 
475  table = ledger->table;
476 
477  gnc_table_leave_update (table, table->current_cursor_loc);
478  save_loc = table->current_cursor_loc;
479 
480  /* Figure out where we are going to */
481  if (ledger->traverse_to_new)
482  {
483  find_entry = blank_entry;
484  }
485  else if (ledger->hint_entry)
486  {
487  find_entry = ledger->hint_entry;
488  }
489  else
490  {
491  find_entry = gnc_entry_ledger_get_current_entry(ledger);
492  /* XXX: get current entry (cursor_hint_xxx) */
493  }
494 
495  /* If the current cursor has changed we save the values for later
496  * possible restoration. */
497  if (gnc_table_current_cursor_changed (table, TRUE) &&
498  (find_entry == gnc_entry_ledger_get_current_entry (ledger)))
499  {
500  cursor_buffer = gnc_cursor_buffer_new ();
501  gnc_table_save_current_cursor (table, cursor_buffer);
502  }
503  else
504  cursor_buffer = NULL;
505 
506  /* disable move callback -- we don't want the cascade of
507  * callbacks while we are fiddling with loading the register */
508  gnc_table_control_allow_move (table->control, FALSE);
509 
510  /* invalidate the cursor */
511  {
512  VirtualLocation virt_loc;
513 
514  virt_loc.vcell_loc.virt_row = -1;
515  virt_loc.vcell_loc.virt_col = -1;
516  virt_loc.phys_row_offset = -1;
517  virt_loc.phys_col_offset = -1;
518 
519  gnc_table_move_cursor_gui (table, virt_loc);
520  }
521 
522  /* make sure that the header is loaded */
523  vcell_loc.virt_row = 0;
524  vcell_loc.virt_col = 0;
525  cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
526  gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
527  vcell_loc.virt_row++;
528 
529  /* get the current time and reset the dividing row */
530  table->model->dividing_row_upper = -1;
531  table->model->dividing_row = -1;
532  table->model->dividing_row_lower = -1;
533  cursor = gnc_table_layout_get_cursor (table->layout, "cursor");
534 
535  /* Populate the table */
536  for (node = entry_list; node; node = node->next)
537  {
538  GncEntry *entry = node->data;
539 
540  /* Don't load the blank entry */
541  if (entry == blank_entry)
542  continue;
543 
544  /* If this is the first load of the ledger, fill the quickfill cells */
545  {
546  /* XXX */
547  }
548 
549  if (entry == find_entry)
550  new_entry_row = vcell_loc.virt_row;
551 
552  gnc_table_set_vcell (table, cursor, gncEntryGetGUID (entry),
553  TRUE, start_primary_color, vcell_loc);
554  vcell_loc.virt_row++;
555 
556  /* Flip color for the next guy */
557  start_primary_color = !start_primary_color;
558  }
559 
560  /* Add the blank entry at the end. */
561  if (blank_entry)
562  {
563  gnc_table_set_vcell (table, cursor, gncEntryGetGUID (blank_entry),
564  TRUE, start_primary_color, vcell_loc);
565 
566  if (find_entry == blank_entry)
567  new_entry_row = vcell_loc.virt_row;
568 
569  vcell_loc.virt_row++;
570  }
571 
572  /* Resize the table */
573  gnc_table_set_size (table, vcell_loc.virt_row, 1);
574 
575  /* Restore the cursor to its rightful position */
576  if (new_entry_row > 0)
577  save_loc.vcell_loc.virt_row = new_entry_row;
578 
579  if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
580  {
581  gnc_table_move_cursor_gui (table, save_loc);
582 
583  if (find_entry == gnc_entry_ledger_get_current_entry (ledger))
584  gnc_table_restore_current_cursor (table, cursor_buffer);
585  }
586 
587  gnc_cursor_buffer_destroy (cursor_buffer);
588  cursor_buffer = NULL;
589 
590  /* Reset the ledger */
591  ledger->traverse_to_new = FALSE;
592  ledger->hint_entry = NULL;
593 
594  /* Set the cell fractions */
595 
596 
597  gnc_table_refresh_gui (table, TRUE);
598  gnc_entry_ledger_show_entry (ledger, table->current_cursor_loc.vcell_loc);
599 
600  /* Set completion character */
602  ((ComboCell *)
603  gnc_table_layout_get_cell (table->layout, ENTRY_IACCT_CELL),
604  gnc_get_account_separator ());
605 
607  ((ComboCell *)
608  gnc_table_layout_get_cell (table->layout, ENTRY_BACCT_CELL),
609  gnc_get_account_separator ());
610 
611  /* enable callback for cursor user-driven moves */
612  gnc_table_control_allow_move (table->control, TRUE);
613 }
614 
615 /* =========================== END OF FILE ========================== */
utility functions for the GnuCash UI
GncTaxIncluded
Definition: gncTaxTable.h:100
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
Create an account-name quick-fill.
void gnc_combo_cell_use_quickfill_cache(ComboCell *cell, QuickFill *shared_qf)
QuickFill * gnc_get_shared_account_name_quickfill(Account *root, const char *key, AccountBoolCB cb, gpointer cb_data)
#define PWARN(format, args...)
Definition: qoflog.h:243
Account handling public routines.
void gnc_combo_cell_set_complete_char(ComboCell *cell, gunichar complete_char)
void gnc_combo_cell_add_menu_item(ComboCell *cell, const char *menustr)
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it...
void gncEntrySetDateGDate(GncEntry *entry, const GDate *date)
Definition: gncEntry.c:505
GNCAccountType
Definition: Account.h:96
Generic api to store and retrieve preferences.
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Definition: gncOwner.c:201
const GncOwner * gncOwnerGetEndOwner(const GncOwner *owner)
Definition: gncOwner.c:550
GncJob * gncOwnerGetJob(const GncOwner *owner)
Definition: gncOwner.c:354
const GncGUID * guid_null(void)
gboolean xaccAccountGetPlaceholder(const Account *acc)
Definition: Account.c:3912
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
QuickFill * gnc_get_shared_entry_desc_quickfill(QofBook *book, const char *key, gboolean use_invoices)
Business Entry Interface.
GncEmployee * gncOwnerGetEmployee(const GncOwner *owner)
Definition: gncOwner.c:368
const gchar * QofLogModule
Definition: qofid.h:89