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