GnuCash  5.6-150-g038405b370+
gncEntryLedgerModel.c
1 /*
2  * gncEntryLedgerModel.c -- Model for GncEntry ledger
3  * Copyright (C) 2001, 2002, 2003 Derek Atkins
4  * Author: Derek Atkins <warlord@MIT.EDU>
5  * Copyright (C) 2017 Aaron Laws
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, contact:
19  *
20  * Free Software Foundation Voice: +1-617-542-5942
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
22  * Boston, MA 02110-1301, USA gnu@gnu.org
23  */
24 
25 #include <config.h>
26 
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 
30 #include "Account.h"
31 #include "gnc-ui-util.h"
32 #include "qof.h" /* for g_strcmp0 */
33 
34 #include "datecell.h"
35 #include "checkboxcell.h"
36 
37 #include "gncEntryLedgerP.h"
38 #include "gncEntryLedgerModel.h"
39 
40 
43 /* GET_LABEL */
44 
45 static const char * get_iacct_label (VirtualLocation virt_loc, gpointer data)
46 {
47  return _("Income Account");
48 }
49 
50 static const char * get_bacct_label (VirtualLocation virt_loc, gpointer data)
51 {
52  return _("Expense Account");
53 }
54 
55 static const char * get_actn_label (VirtualLocation virt_loc, gpointer data)
56 {
57  return _("Action");
58 }
59 
60 static const char * get_date_label (VirtualLocation virt_loc, gpointer data)
61 {
62  return _("Date");
63 }
64 
65 static const char * get_desc_label (VirtualLocation virt_loc, gpointer data)
66 {
67  return _("Description");
68 }
69 
70 static const char * get_disc_label (VirtualLocation virt_loc, gpointer data)
71 {
72  return _("Discount");
73 }
74 
75 static const char * get_distype_label (VirtualLocation virt_loc, gpointer data)
76 {
77  return _("Discount Type");
78 }
79 
80 static const char * get_dishow_label (VirtualLocation virt_loc, gpointer data)
81 {
82  return _("Discount How");
83 }
84 
85 static const char * get_pric_label (VirtualLocation virt_loc, gpointer data)
86 {
87  return _("Unit Price");
88 }
89 
90 static const char * get_qty_label (VirtualLocation virt_loc, gpointer data)
91 {
92  return _("Quantity");
93 }
94 
95 static const char * get_taxtable_label (VirtualLocation virt_loc, gpointer data)
96 {
97  return _("Tax Table");
98 }
99 
100 static const char * get_taxable_label (VirtualLocation virt_loc, gpointer data)
101 {
102  return _("Taxable?");
103 }
104 
105 static const char * get_taxincluded_label (VirtualLocation virt_loc, gpointer data)
106 {
107  return _("Tax Included?");
108 }
109 
110 static const char * get_inv_label (VirtualLocation virt_loc, gpointer data)
111 {
112  return _("Invoiced?");
113 }
114 
115 static const char * get_value_label (VirtualLocation virt_loc, gpointer data)
116 {
117  return _("Subtotal");
118 }
119 
120 static const char * get_taxval_label (VirtualLocation virt_loc, gpointer data)
121 {
122  return _("Tax");
123 }
124 
125 static const char * get_billable_label (VirtualLocation virt_loc, gpointer data)
126 {
127  return _("Billable?");
128 }
129 
130 static const char * get_payment_label (VirtualLocation virt_loc, gpointer data)
131 {
132  return _("Payment");
133 }
134 
135 /* GET_ENTRY */
136 
137 static const char * get_iacct_entry (VirtualLocation virt_loc,
138  gboolean translate,
139  gboolean *conditionally_changed,
140  gpointer user_data)
141 {
142  static char *name = NULL;
143 
144  GncEntryLedger *ledger = user_data;
145  GncEntry *entry;
146 
147  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
148 
149  g_free (name);
150  name = gnc_get_account_name_for_register (gncEntryGetInvAccount (entry));
151  return name;
152 }
153 
154 static const char * get_bacct_entry (VirtualLocation virt_loc,
155  gboolean translate,
156  gboolean *conditionally_changed,
157  gpointer user_data)
158 {
159  static char *name = NULL;
160 
161  GncEntryLedger *ledger = user_data;
162  GncEntry *entry;
163 
164  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
165 
166  g_free (name);
167  name = gnc_get_account_name_for_register (gncEntryGetBillAccount (entry));
168  return name;
169 }
170 
171 static const char * get_actn_entry (VirtualLocation virt_loc,
172  gboolean translate,
173  gboolean *conditionally_changed,
174  gpointer user_data)
175 {
176  GncEntryLedger *ledger = user_data;
177  GncEntry *entry;
178 
179  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
180  return gncEntryGetAction (entry);
181 }
182 
183 static const char * get_date_entry (VirtualLocation virt_loc,
184  gboolean translate,
185  gboolean *conditionally_changed,
186  gpointer user_data)
187 {
188  GncEntryLedger *ledger = user_data;
189  GncEntry *entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
190  time64 time = gncEntryGetDate (entry);
191  static gchar dateBuff [MAX_DATE_LENGTH+1];
192  memset (dateBuff, 0, sizeof (dateBuff));
193  qof_print_date_buff (dateBuff, MAX_DATE_LENGTH, time);
194  return dateBuff;
195 }
196 
197 static const char * get_desc_entry (VirtualLocation virt_loc,
198  gboolean translate,
199  gboolean *conditionally_changed,
200  gpointer user_data)
201 {
202  GncEntryLedger *ledger = user_data;
203  GncEntry *entry;
204 
205  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
206  return gncEntryGetDescription (entry);
207 }
208 
209 static const char * get_disc_entry (VirtualLocation virt_loc,
210  gboolean translate,
211  gboolean *conditionally_changed,
212  gpointer user_data)
213 {
214  GncEntryLedger *ledger = user_data;
215  GncEntry *entry;
216  gnc_numeric discount;
217 
218  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
219  discount = gncEntryGetInvDiscount (entry);
220  if (gnc_numeric_zero_p (discount))
221  return NULL;
222 
223  return xaccPrintAmount (discount, gnc_default_print_info (FALSE));
224 }
225 
226 static const char * get_distype_entry (VirtualLocation virt_loc,
227  gboolean translate,
228  gboolean *conditionally_changed,
229  gpointer user_data)
230 {
231  GncEntryLedger *ledger = user_data;
232  GncEntry *entry;
233  char type;
234 
235  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
236  type = gncEntryGetInvDiscountType (entry);
237 
238  if (translate)
239  {
240  return gnc_entry_ledger_type_string_getter (type + '0');
241  }
242  else
243  {
244  static char s[2];
245  s[0] = '0' + type;
246  s[1] = '\0';
247  return s;
248  }
249 }
250 
251 static const char * get_dishow_entry (VirtualLocation virt_loc,
252  gboolean translate,
253  gboolean *conditionally_changed,
254  gpointer user_data)
255 {
256  GncEntryLedger *ledger = user_data;
257  GncEntry *entry;
258  char type;
259 
260  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
261  type = gncEntryGetInvDiscountHow (entry);
262 
263  if (translate)
264  {
265  return gnc_entry_ledger_how_string_getter (type + '0');
266  }
267  else
268  {
269  static char s[2];
270  s[0] = '0' + type;
271  s[1] = '\0';
272  return s;
273  }
274 }
275 
276 static const char * get_pric_entry (VirtualLocation virt_loc,
277  gboolean translate,
278  gboolean *conditionally_changed,
279  gpointer user_data)
280 {
281  GncEntryLedger *ledger = user_data;
282  GncEntry *entry;
283  gnc_numeric price;
284 
285  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
286  if (ledger->is_cust_doc)
287  price = gncEntryGetInvPrice (entry);
288  else
289  price = gncEntryGetBillPrice (entry);
290 
291  if (gnc_numeric_zero_p (price))
292  return NULL;
293 
294  return xaccPrintAmount (price, gnc_default_print_info (FALSE));
295 }
296 
297 static const char * get_qty_entry (VirtualLocation virt_loc,
298  gboolean translate,
299  gboolean *conditionally_changed,
300  gpointer user_data)
301 {
302  GncEntryLedger *ledger = user_data;
303  GncEntry *entry;
304  gnc_numeric qty;
305 
306  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
307  qty = gncEntryGetDocQuantity (entry, ledger->is_credit_note);
308 
309  if (gnc_numeric_zero_p (qty))
310  return NULL;
311 
312  return xaccPrintAmount (qty, gnc_default_print_info (FALSE));
313 }
314 
315 static const char * get_taxable_entry (VirtualLocation virt_loc,
316  gboolean translate,
317  gboolean *conditionally_changed,
318  gpointer user_data)
319 {
320  GncEntryLedger *ledger = user_data;
321  GncEntry *entry;
322  gboolean taxable;
323 
324  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
325  if (ledger->is_cust_doc)
326  taxable = gncEntryGetInvTaxable (entry);
327  else
328  taxable = gncEntryGetBillTaxable (entry);
329 
330  return gnc_checkbox_cell_get_string (taxable);
331 }
332 
333 static gboolean
334 gnc_entry_ledger_get_taxable_value (VirtualLocation virt_loc,
335  gboolean translate,
336  gboolean *conditionally_changed,
337  gpointer user_data)
338 {
339  GncEntryLedger *ledger = user_data;
340  gboolean is_current;
341 
342  is_current = virt_cell_loc_equal(ledger->table->current_cursor_loc.vcell_loc,
343  virt_loc.vcell_loc);
344  if (is_current)
345  return gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
346  else
347  {
348  const char *valstr =
349  get_taxable_entry (virt_loc, translate, conditionally_changed,
350  user_data);
351  if (valstr && *valstr != ' ')
352  return TRUE;
353  }
354  return FALSE;
355 }
356 
357 static const char * get_taxtable_entry (VirtualLocation virt_loc,
358  gboolean translate,
359  gboolean *conditionally_changed,
360  gpointer user_data)
361 {
362  GncEntryLedger *ledger = user_data;
363  GncEntry *entry;
365  gboolean taxable;
366 
367  /* load the cell properly; just shadow the value */
368  if (!conditionally_changed)
369  {
370  taxable = gnc_entry_ledger_get_taxable_value (virt_loc, translate,
371  conditionally_changed,
372  user_data);
373  if (!taxable)
374  return NULL;
375  }
376 
377  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
378  if (ledger->is_cust_doc)
379  table = gncEntryGetInvTaxTable (entry);
380  else
381  table = gncEntryGetBillTaxTable (entry);
382 
383  return gncTaxTableGetName (table);
384 }
385 
386 static const char * get_taxincluded_entry (VirtualLocation virt_loc,
387  gboolean translate,
388  gboolean *conditionally_changed,
389  gpointer user_data)
390 {
391  GncEntryLedger *ledger = user_data;
392  GncEntry *entry;
393  gboolean taxable, taxincluded;
394 
395  /* load the cell properly; just shadow the value */
396  if (!conditionally_changed)
397  {
398  taxable = gnc_entry_ledger_get_taxable_value (virt_loc, translate,
399  conditionally_changed,
400  user_data);
401  if (!taxable)
402  return NULL;
403  }
404 
405  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
406  if (ledger->is_cust_doc)
407  taxincluded = gncEntryGetInvTaxIncluded (entry);
408  else
409  taxincluded = gncEntryGetBillTaxIncluded (entry);
410 
411  return gnc_checkbox_cell_get_string (taxincluded);
412 }
413 
414 static const char * get_inv_entry (VirtualLocation virt_loc,
415  gboolean translate,
416  gboolean *conditionally_changed,
417  gpointer user_data)
418 {
419  GncEntryLedger *ledger = user_data;
420  GncEntry *entry;
421 
422  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
423 
424  return gnc_checkbox_cell_get_string (gncEntryGetInvoice (entry) != NULL);
425 
426  /* XXX: what if this entry doesn't belong to this invoice?
427  * Or, better question, what if this is the blank_entry on
428  * an invoice page? For the latter, don't worry about it;
429  * it will be added automatically during the Save operation
430  */
431 }
432 
433 static const char * get_value_entry (VirtualLocation virt_loc,
434  gboolean translate,
435  gboolean *conditionally_changed,
436  gpointer user_data)
437 {
438  GncEntryLedger *ledger = user_data;
439  gnc_numeric value;
440 
441  /* Check if this is the current cursor */
442  if (virt_cell_loc_equal (ledger->table->current_cursor_loc.vcell_loc,
443  virt_loc.vcell_loc))
444  {
445  /* Sign attention: this function works with values as seen
446  * on-screen in the ledger, so they are always in the proper sign.
447  */
448  gnc_entry_ledger_compute_value (ledger, &value, NULL);
449  }
450  else
451  {
452  GncEntry *entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
453 
454  if (entry == gnc_entry_ledger_get_blank_entry (ledger))
455  return NULL;
456 
457  /* Ledger should display values with the same sign as on the document
458  * so get the document value instead of the internal value here.
459  */
460  value = gncEntryGetDocValue (entry, TRUE, ledger->is_cust_doc, ledger->is_credit_note);
461  }
462 
463  return xaccPrintAmount (value, gnc_default_print_info (FALSE));
464 }
465 
466 static const char * get_taxval_entry (VirtualLocation virt_loc,
467  gboolean translate,
468  gboolean *conditionally_changed,
469  gpointer user_data)
470 {
471  GncEntryLedger *ledger = user_data;
472  gnc_numeric value;
473 
474  /* Check if this is the current cursor */
475  if (virt_cell_loc_equal (ledger->table->current_cursor_loc.vcell_loc,
476  virt_loc.vcell_loc))
477  {
478  /* Sign attention: this function works with values as seen
479  * on-screen in the ledger, so they are always in the proper sign.
480  */
481  gnc_entry_ledger_compute_value (ledger, NULL, &value);
482  }
483  else
484  {
485  GncEntry *entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
486 
487  if (entry == gnc_entry_ledger_get_blank_entry (ledger))
488  return NULL;
489 
490  /* Ledger should display values with the same sign as on the document
491  * so get the document value instead of the internal value here.
492  */
493  value = gncEntryGetDocTaxValue (entry, TRUE, ledger->is_cust_doc, ledger->is_credit_note);
494  }
495 
496  return xaccPrintAmount (value, gnc_default_print_info (FALSE));
497 }
498 
499 static const char * get_billable_entry (VirtualLocation virt_loc,
500  gboolean translate,
501  gboolean *conditionally_changed,
502  gpointer user_data)
503 {
504  GncEntryLedger *ledger = user_data;
505  GncEntry *entry;
506 
507  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
508  return gnc_checkbox_cell_get_string (gncEntryGetBillable (entry));
509 }
510 
511 static const char * get_payment_entry (VirtualLocation virt_loc,
512  gboolean translate,
513  gboolean *conditionally_changed,
514  gpointer user_data)
515 {
516  GncEntryLedger *ledger = user_data;
517  GncEntry *entry;
518  GncEntryPaymentType type;
519 
520  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
521 
522  if (!entry)
523  return "";
524 
525  type = gncEntryGetBillPayment (entry);
526 
527  switch (type)
528  {
529  case GNC_PAYMENT_CASH:
530  return _("Cash");
531  case GNC_PAYMENT_CARD:
532  return _("Charge");
533  default:
534  g_warning ("Invalid payment type: %d", type);
535  return "";
536  }
537 }
538 
539 /* GET_HELP */
540 
541 static char * get_acct_help (VirtualLocation virt_loc, gpointer user_data)
542 {
543  const char *help;
544  GncEntryLedger *ledger = user_data;
545 
546  help = gnc_table_get_entry (ledger->table, virt_loc);
547  if (!help || *help == '\0')
548  help = _("Enter the income/expense account for the Entry, "
549  "or choose one from the list");
550 
551  return g_strdup (help);
552 }
553 
554 static char * get_actn_help (VirtualLocation virt_loc, gpointer user_data)
555 {
556  GncEntryLedger *ledger = user_data;
557  const char *help;
558 
559  help = gnc_table_get_entry (ledger->table, virt_loc);
560  if (!help || *help == '\0')
561  help = _("Enter the type of Entry");
562 
563  return g_strdup (help);
564 }
565 
566 static char * get_date_help (VirtualLocation virt_loc, gpointer user_data)
567 {
568  GncEntryLedger *ledger = user_data;
569  BasicCell *cell;
570  time64 cell_time;
571 
572  cell = gnc_table_get_cell (ledger->table, virt_loc);
573  if (!cell || !cell->value || *cell->value == '\0')
574  return NULL;
575 
576  gnc_date_cell_get_date ((DateCell *) cell, &cell_time, FALSE);
577  return gnc_print_time64 (cell_time, _("%A %d %B %Y"));
578 }
579 
580 static char * get_desc_help (VirtualLocation virt_loc, gpointer user_data)
581 {
582  GncEntryLedger *ledger = user_data;
583  const char *help;
584 
585  help = gnc_table_get_entry (ledger->table, virt_loc);
586  if (!help || *help == '\0')
587  help = _("Enter the Entry Description");
588 
589  return g_strdup (help);
590 }
591 
592 static char * get_disc_help (VirtualLocation virt_loc, gpointer user_data)
593 {
594  GncEntryLedger *ledger = user_data;
595  const char *help;
596  gint type;
597 
598  type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);
599 
600  switch (type)
601  {
602  case GNC_AMT_TYPE_VALUE:
603  help = _("Enter the Discount Amount");
604  break;
606  help = _("Enter the Discount Percent");
607  break;
608  default:
609  help = _("Enter the Discount … unknown type");
610  break;
611  }
612 
613  return g_strdup (help);
614 }
615 
616 static char * get_distype_help (VirtualLocation virt_loc, gpointer user_data)
617 {
618  GncEntryLedger *ledger = user_data;
619  const char *help;
620  gint type;
621 
622  type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);
623 
624  switch (type)
625  {
626  case GNC_AMT_TYPE_VALUE:
627  help = _("Discount Type: Monetary Value");
628  break;
630  help = _("Discount Type: Percent");
631  break;
632  default:
633  help = _("Select the Discount Type");
634  break;
635  }
636  return g_strdup (help);
637 }
638 
639 static char * get_dishow_help (VirtualLocation virt_loc, gpointer user_data)
640 {
641  GncEntryLedger *ledger = user_data;
642  const char *help;
643  gint type;
644 
645  type = gnc_entry_ledger_get_type (ledger, ENTRY_DISHOW_CELL);
646 
647  switch (type)
648  {
649  case GNC_DISC_PRETAX:
650  help = _("Tax computed after discount is applied");
651  break;
652  case GNC_DISC_SAMETIME:
653  help = _("Discount and tax both applied on pretax value");
654  break;
655  case GNC_DISC_POSTTAX:
656  help = _("Discount computed after tax is applied");
657  break;
658  default:
659  help = _("Select how to compute the Discount and Taxes");
660  break;
661  }
662  return g_strdup (help);
663 }
664 
665 static char * get_pric_help (VirtualLocation virt_loc, gpointer user_data)
666 {
667  GncEntryLedger *ledger = user_data;
668  const char *help;
669 
670  help = gnc_table_get_entry (ledger->table, virt_loc);
671  if (!help || *help == '\0')
672  help = _("Enter the unit-Price for this Entry");
673 
674  return g_strdup (help);
675 }
676 
677 static char * get_qty_help (VirtualLocation virt_loc, gpointer user_data)
678 {
679  GncEntryLedger *ledger = user_data;
680  const char *help;
681 
682  help = gnc_table_get_entry (ledger->table, virt_loc);
683  if (!help || *help == '\0')
684  help = _("Enter the Quantity of units for this Entry");
685 
686  return g_strdup (help);
687 }
688 
689 static char * get_taxtable_help (VirtualLocation virt_loc, gpointer user_data)
690 {
691  GncEntryLedger *ledger = user_data;
692  const char *help;
693 
694  help = gnc_table_get_entry (ledger->table, virt_loc);
695  if (!help || *help == '\0')
696  help = _("Enter the Tax Table to apply to this entry");
697 
698  return g_strdup (help);
699 }
700 
701 static char * get_taxable_help (VirtualLocation virt_loc, gpointer user_data)
702 {
703  const char *help;
704 
705  help = _("Is this entry taxable?");
706 
707  return g_strdup (help);
708 }
709 
710 static char * get_taxincluded_help (VirtualLocation virt_loc, gpointer user_data)
711 {
712  const char *help;
713 
714  help = _("Is the tax already included in the price of this entry?");
715 
716  return g_strdup (help);
717 }
718 
719 static char * get_inv_help (VirtualLocation virt_loc, gpointer user_data)
720 {
721  GncEntryLedger *ledger = user_data;
722  const char *help;
723 
724  switch (ledger->type)
725  {
726  case GNCENTRY_ORDER_ENTRY:
727  case GNCENTRY_ORDER_VIEWER:
728  case GNCENTRY_BILL_ENTRY:
729  case GNCENTRY_BILL_VIEWER:
730  case GNCENTRY_EXPVOUCHER_ENTRY:
731  case GNCENTRY_EXPVOUCHER_VIEWER:
732  help = _("Is this entry invoiced?");
733  break;
734  case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
735  case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
736  case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
737  case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
738  help = _("Is this entry credited?");
739  break;
740  case GNCENTRY_INVOICE_ENTRY:
741  case GNCENTRY_INVOICE_VIEWER:
742  help = _("Include this entry on this invoice?");
743  break;
744  case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
745  case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
746  help = _("Include this entry on this credit note?");
747  break;
748  default:
749  help = _("Unknown EntryLedger Type");
750  }
751 
752  return g_strdup (help);
753 }
754 
755 static char * get_value_help (VirtualLocation virt_loc, gpointer user_data)
756 {
757  GncEntryLedger *ledger = user_data;
758  const char *help;
759 
760  help = gnc_table_get_entry (ledger->table, virt_loc);
761  if (!help || *help == '\0')
762  help = _("The subtotal value of this entry");
763 
764  return g_strdup (help);
765 }
766 
767 static char * get_taxval_help (VirtualLocation virt_loc, gpointer user_data)
768 {
769  GncEntryLedger *ledger = user_data;
770  const char *help;
771 
772  help = gnc_table_get_entry (ledger->table, virt_loc);
773  if (!help || *help == '\0')
774  help = _("The total tax of this entry ");
775 
776  return g_strdup (help);
777 }
778 
779 static char * get_billable_help (VirtualLocation virt_loc, gpointer user_data)
780 {
781  const char *help;
782 
783  help = _("Is this entry billable to a customer or job?");
784 
785  return g_strdup (help);
786 }
787 
788 static char * get_payment_help (VirtualLocation virt_loc, gpointer user_data)
789 {
790  const char *help;
791 
792  help = _("How did you pay for this item?");
793 
794  return g_strdup (help);
795 }
796 
797 /* GET_IO_FLAGS */
798 
799 static CellIOFlags get_standard_io_flags (VirtualLocation virt_loc,
800  gpointer user_data)
801 {
802  GncEntryLedger *ledger = user_data;
803  switch (ledger->type)
804  {
805  case GNCENTRY_ORDER_ENTRY:
806  case GNCENTRY_BILL_ENTRY:
807  case GNCENTRY_EXPVOUCHER_ENTRY:
808  {
809  GncEntry *entry =
810  gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
811 
812  /*
813  * If the type is an order_entry and the entry was invoiced,
814  * make the entry immutable
815  */
816  if (gncEntryGetInvoice (entry) != NULL)
817  return XACC_CELL_ALLOW_SHADOW;
818  }
819  /* FALL THROUGH */
820  default:
821  return XACC_CELL_ALLOW_ALL;
822  }
823 }
824 
825 static CellIOFlags get_typecell_io_flags (VirtualLocation virt_loc,
826  gpointer user_data)
827 {
828  return (get_standard_io_flags (virt_loc, user_data) |
829  XACC_CELL_ALLOW_EXACT_ONLY);
830 }
831 
832 static CellIOFlags get_inv_io_flags (VirtualLocation virt_loc,
833  gpointer user_data)
834 {
835  GncEntryLedger *ledger = user_data;
836 
837  switch (ledger->type)
838  {
839  case GNCENTRY_INVOICE_ENTRY:
840  case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
841  {
842  /* This cell should be immutable IFF this entry is attached to
843  * a bill, order, or something else.
844  */
845  GncEntry * entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
846 
847  if ((gncEntryGetOrder (entry) != NULL) || (gncEntryGetBill (entry) != NULL))
848  return XACC_CELL_ALLOW_ALL | XACC_CELL_ALLOW_EXACT_ONLY;
849 
850  }
851  /* FALL THROUGH */
852  default:
853  return XACC_CELL_ALLOW_SHADOW;
854  }
855 }
856 
857 static CellIOFlags get_value_io_flags (VirtualLocation virt_loc,
858  gpointer user_data)
859 {
860  return XACC_CELL_ALLOW_SHADOW;
861 }
862 
863 static CellIOFlags get_tax_io_flags (VirtualLocation virt_loc,
864  gpointer user_data)
865 {
866  GncEntryLedger *ledger = user_data;
867  gboolean taxable;
868 
869  taxable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
870 
871  /* Only print the taxtable and taxincluded cells if taxable is true */
872  if (taxable)
873  return get_standard_io_flags (virt_loc, user_data);
874 
875  /* Shadow the value, so the cell is loaded properly */
876  return XACC_CELL_ALLOW_SHADOW;
877 }
878 
879 static CellIOFlags get_taxincluded_io_flags (VirtualLocation virt_loc,
880  gpointer user_data)
881 {
882  CellIOFlags flags = get_tax_io_flags (virt_loc, user_data);
883  if (flags == XACC_CELL_ALLOW_SHADOW)
884  return flags;
885  return flags | XACC_CELL_ALLOW_EXACT_ONLY;
886 }
887 
888 static CellIOFlags get_qty_io_flags (VirtualLocation virt_loc, gpointer user_data)
889 {
890  GncEntryLedger *ledger = user_data;
891  GncEntry *entry;
892  CellIOFlags flags = get_standard_io_flags (virt_loc, user_data);
893 
894  /* If this isn't an invoice, or the flags are already read-only ... */
895  if (!ledger->is_cust_doc || flags == XACC_CELL_ALLOW_SHADOW)
896  return flags;
897 
898  /* ok, if this is an invoice ledger AND this entry is attached to a
899  * bill (i.e. it's billable), freeze the quantity
900  */
901  entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
902  if (gncEntryGetBillable (entry))
903  return XACC_CELL_ALLOW_SHADOW;
904 
905  return flags;
906 }
907 
908 /* GET COLORS */
909 
910 static guint32
911 gnc_entry_ledger_get_cell_color_internal (VirtualLocation virt_loc,
912  GncEntryLedger *ledger)
913 {
914  VirtualCell *vcell;
915  gboolean is_current;
916  guint32 colorbase = 0;
917 
918  /* a bit of enum arithmetic */
919 
920  // There are negative numbers
921 
922  if (!ledger)
923  return (colorbase + COLOR_UNDEFINED);
924 
925  if (gnc_table_virtual_location_in_header (ledger->table, virt_loc))
926  return (colorbase + COLOR_HEADER);
927 
928  vcell = gnc_table_get_virtual_cell (ledger->table, virt_loc.vcell_loc);
929  if (!vcell || !vcell->cellblock)
930  return (colorbase + COLOR_UNDEFINED);
931 
932  if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
933  (virt_loc.phys_col_offset > vcell->cellblock->stop_col))
934  return (colorbase + COLOR_UNDEFINED);
935 
936  is_current = virt_cell_loc_equal (ledger->table->current_cursor_loc.vcell_loc,
937  virt_loc.vcell_loc);
938 
939  if (is_current)
940  return vcell->start_primary_color ?
941  (colorbase + COLOR_PRIMARY_ACTIVE) :
942  (colorbase + COLOR_SECONDARY_ACTIVE);
943 
944  return vcell->start_primary_color ?
945  (colorbase + COLOR_PRIMARY) : (colorbase + COLOR_SECONDARY);
946 
947 }
948 
949 static guint32
950 gnc_entry_ledger_get_cell_color (VirtualLocation virt_loc,
951  gboolean *hatching, gpointer user_data)
952 {
953  GncEntryLedger *ledger = user_data;
954 
955  if (hatching)
956  *hatching = FALSE;
957 
958  return gnc_entry_ledger_get_cell_color_internal (virt_loc, ledger);
959 }
960 
961 /* SAVE CELLS */
962 
963 static void gnc_entry_ledger_save_cells (gpointer save_data,
964  gpointer user_data)
965 {
966  GncEntryLedger *ledger = user_data;
967  GncEntry *entry = save_data;
968 
969  g_return_if_fail (entry != NULL);
970 
971  /* copy the contents from the cursor to the split */
972 
973  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
974  ENTRY_IACCT_CELL, TRUE))
975  {
976  Account *acc;
977 
978  acc = gnc_entry_ledger_get_account (ledger, ENTRY_IACCT_CELL);
979 
980  if (acc != NULL)
981  gncEntrySetInvAccount (entry, acc);
982  }
983 
984  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
985  ENTRY_BACCT_CELL, TRUE))
986  {
987  Account *acc;
988 
989  acc = gnc_entry_ledger_get_account (ledger, ENTRY_BACCT_CELL);
990 
991  if (acc != NULL)
992  gncEntrySetBillAccount (entry, acc);
993  }
994 
995  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
996  ENTRY_ACTN_CELL, TRUE))
997  {
998  const char *value;
999 
1000  value = gnc_table_layout_get_cell_value (ledger->table->layout,
1001  ENTRY_ACTN_CELL);
1002  gncEntrySetAction (entry, value);
1003  }
1004 
1005  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1006  ENTRY_DATE_CELL, TRUE))
1007  {
1008  BasicCell *cell;
1009  time64 cell_time;
1010 
1011  cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DATE_CELL);
1012 
1013  gnc_date_cell_get_date ((DateCell *) cell, &cell_time, TRUE);
1014 
1015  /* commit any pending changes */
1016  gnc_date_cell_commit ((DateCell *) cell);
1017 
1018  /* Note use of time64CanonicalDayTime to set time part to midday */
1019  gncEntrySetDate (entry, time64CanonicalDayTime(cell_time));
1020  }
1021 
1022  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1023  ENTRY_DESC_CELL, TRUE))
1024  {
1025  const char *value;
1026 
1027  value = gnc_table_layout_get_cell_value (ledger->table->layout,
1028  ENTRY_DESC_CELL);
1029  gncEntrySetDescription (entry, value);
1030  }
1031 
1032  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1033  ENTRY_DISC_CELL, TRUE))
1034  {
1035  gnc_numeric amount;
1036 
1037  if (gnc_entry_ledger_get_numeric (ledger, ENTRY_DISC_CELL, &amount))
1038  gncEntrySetInvDiscount (entry, amount);
1039  }
1040 
1041  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1042  ENTRY_DISTYPE_CELL, TRUE))
1043  {
1044  gint type;
1045 
1046  type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);
1047 
1048  if (type != -1)
1049  gncEntrySetInvDiscountType (entry, type);
1050  }
1051 
1052  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1053  ENTRY_DISHOW_CELL, TRUE))
1054  {
1055  gint type;
1056 
1057  type = gnc_entry_ledger_get_type (ledger, ENTRY_DISHOW_CELL);
1058 
1059  if (type != -1)
1060  gncEntrySetInvDiscountHow (entry, type);
1061  }
1062 
1063  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1064  ENTRY_QTY_CELL, TRUE))
1065  {
1066  gnc_numeric amount;
1067 
1068  if (gnc_entry_ledger_get_numeric (ledger, ENTRY_QTY_CELL, &amount))
1069  {
1070  gncEntrySetDocQuantity (entry, amount, ledger->is_credit_note);
1071  }
1072  }
1073 
1074  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1075  ENTRY_BILLABLE_CELL, TRUE))
1076  {
1077  gboolean billable;
1078 
1079  billable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_BILLABLE_CELL);
1080  gncEntrySetBillable (entry, billable);
1081  }
1082 
1083  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1084  ENTRY_PAYMENT_CELL, TRUE))
1085  {
1086  const char *value;
1087 
1088  value = gnc_table_layout_get_cell_value (ledger->table->layout,
1089  ENTRY_PAYMENT_CELL);
1090  if (!g_strcmp0 (value, _("Cash")))
1091  gncEntrySetBillPayment (entry, GNC_PAYMENT_CASH);
1092  else if (!g_strcmp0 (value, _("Charge")))
1093  gncEntrySetBillPayment (entry, GNC_PAYMENT_CARD);
1094  else
1095  g_warning ("Invalid Payment cell: %s", value ? value : "(null)");
1096  }
1097 
1098  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1099  ENTRY_PRIC_CELL, TRUE))
1100  {
1101  gnc_numeric amount;
1102 
1103  if (gnc_entry_ledger_get_numeric (ledger, ENTRY_PRIC_CELL, &amount))
1104  {
1105  if (ledger->is_cust_doc)
1106  gncEntrySetInvPrice (entry, amount);
1107  else
1108  gncEntrySetBillPrice (entry, amount);
1109  }
1110  }
1111 
1112  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1113  ENTRY_TAXABLE_CELL, TRUE))
1114  {
1115  gboolean taxable;
1116 
1117  taxable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
1118  if (ledger->is_cust_doc)
1119  gncEntrySetInvTaxable (entry, taxable);
1120  else
1121  gncEntrySetBillTaxable (entry, taxable);
1122  }
1123 
1124  /* XXX: Only (re-set) these if taxable is TRUE? */
1125  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1126  ENTRY_TAXTABLE_CELL, TRUE))
1127  {
1128  GncTaxTable *table;
1129 
1130  table = gnc_entry_ledger_get_taxtable (ledger, ENTRY_TAXTABLE_CELL);
1131  if (table)
1132  {
1133  if (ledger->is_cust_doc)
1134  gncEntrySetInvTaxTable (entry, table);
1135  else
1136  gncEntrySetBillTaxTable (entry, table);
1137  }
1138  }
1139 
1140  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
1141  ENTRY_TAXINCLUDED_CELL, TRUE))
1142  {
1143  gboolean taxincluded;
1144 
1145  taxincluded = gnc_entry_ledger_get_checkmark (ledger,
1146  ENTRY_TAXINCLUDED_CELL);
1147  if (ledger->is_cust_doc)
1148  gncEntrySetInvTaxIncluded (entry, taxincluded);
1149  else
1150  gncEntrySetBillTaxIncluded (entry, taxincluded);
1151  }
1152 
1153  if (ledger->type == GNCENTRY_INVOICE_ENTRY ||
1154  ledger->type == GNCENTRY_CUST_CREDIT_NOTE_ENTRY)
1155  {
1156  gboolean inv_value;
1157 
1158  inv_value = gnc_entry_ledger_get_checkmark (ledger, ENTRY_INV_CELL);
1159 
1160  if (inv_value)
1161  {
1162  /* Add this to the invoice (if it's not already attached) */
1163  if (gncEntryGetInvoice (entry) == NULL)
1164  gncInvoiceAddEntry (ledger->invoice, entry);
1165 
1166  }
1167  else
1168  {
1169  /* Remove from the invoice iff we're attached to an order or bill */
1170  if ((gncEntryGetOrder (entry) != NULL) ||
1171  (gncEntryGetBill (entry) != NULL))
1172  gncInvoiceRemoveEntry (ledger->invoice, entry);
1173  }
1174  }
1175 }
1176 
1177 /* Set Cell Handlers */
1178 
1179 static void gnc_entry_ledger_model_new_handlers (TableModel *model,
1180  GncEntryLedgerType type)
1181 {
1182  struct model_desc
1183  {
1184  const char * cell;
1185  gpointer entry_handler;
1186  gpointer label_handler;
1187  gpointer help_handler;
1188  gpointer io_flags_handler;
1189  } models[] =
1190  {
1191  { ENTRY_IACCT_CELL, get_iacct_entry, get_iacct_label, get_acct_help, get_standard_io_flags },
1192  { ENTRY_BACCT_CELL, get_bacct_entry, get_bacct_label, get_acct_help, get_standard_io_flags },
1193  { ENTRY_ACTN_CELL, get_actn_entry, get_actn_label, get_actn_help, get_standard_io_flags },
1194  { ENTRY_DATE_CELL, get_date_entry, get_date_label, get_date_help, get_standard_io_flags },
1195  { ENTRY_DESC_CELL, get_desc_entry, get_desc_label, get_desc_help, get_standard_io_flags },
1196  { ENTRY_DISC_CELL, get_disc_entry, get_disc_label, get_disc_help, get_standard_io_flags },
1197  { ENTRY_DISTYPE_CELL, get_distype_entry, get_distype_label, get_distype_help, get_typecell_io_flags },
1198  { ENTRY_DISHOW_CELL, get_dishow_entry, get_dishow_label, get_dishow_help, get_typecell_io_flags },
1199  { ENTRY_PRIC_CELL, get_pric_entry, get_pric_label, get_pric_help, get_standard_io_flags },
1200  { ENTRY_QTY_CELL, get_qty_entry, get_qty_label, get_qty_help, get_qty_io_flags },
1201  { ENTRY_TAXABLE_CELL, get_taxable_entry, get_taxable_label, get_taxable_help, get_typecell_io_flags },
1202  { ENTRY_TAXTABLE_CELL, get_taxtable_entry, get_taxtable_label, get_taxtable_help, get_tax_io_flags },
1203  { ENTRY_TAXINCLUDED_CELL, get_taxincluded_entry, get_taxincluded_label, get_taxincluded_help, get_taxincluded_io_flags },
1204  { ENTRY_INV_CELL, get_inv_entry, get_inv_label, get_inv_help, get_inv_io_flags },
1205  { ENTRY_VALUE_CELL, get_value_entry, get_value_label, get_value_help, get_value_io_flags },
1206  { ENTRY_TAXVAL_CELL, get_taxval_entry, get_taxval_label, get_taxval_help, get_value_io_flags },
1207  { ENTRY_BILLABLE_CELL, get_billable_entry, get_billable_label, get_billable_help, get_typecell_io_flags },
1208  { ENTRY_PAYMENT_CELL, get_payment_entry, get_payment_label, get_payment_help, get_standard_io_flags },
1209  };
1210  unsigned int i;
1211 
1212  // Set the cell color handler
1213  gnc_table_model_set_default_cell_color_handler (model, gnc_entry_ledger_get_cell_color);
1214 
1215  for (i = 0; i < (sizeof(models) / sizeof(*models)); i++)
1216  {
1217  if (models[i].entry_handler)
1218  gnc_table_model_set_entry_handler (model, models[i].entry_handler,
1219  models[i].cell);
1220  if (models[i].label_handler)
1221  gnc_table_model_set_label_handler (model, models[i].label_handler,
1222  models[i].cell);
1223  if (models[i].help_handler)
1224  gnc_table_model_set_help_handler (model, models[i].help_handler,
1225  models[i].cell);
1226  if (models[i].io_flags_handler)
1227  gnc_table_model_set_io_flags_handler (model, models[i].io_flags_handler,
1228  models[i].cell);
1229  } /* for */
1230 
1231  /*
1232  model->cell_data_allocator = ;
1233  model->cell_data_deallocator = ;
1234  model->cell_data_copy = ;
1235  */
1236 
1237  gnc_table_model_set_post_save_handler (model, gnc_entry_ledger_save_cells);
1238 
1239  switch (type)
1240  {
1241  case GNCENTRY_ORDER_VIEWER:
1242  case GNCENTRY_INVOICE_VIEWER:
1243  case GNCENTRY_BILL_VIEWER:
1244  case GNCENTRY_EXPVOUCHER_VIEWER:
1245  case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
1246  case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
1247  case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
1248  /* make this table read-only */
1249  gnc_table_model_set_read_only (model, TRUE);
1250  break;
1251  default:
1252  break;
1253  }
1254 }
1255 
1258 TableModel * gnc_entry_ledger_model_new (GncEntryLedgerType type)
1259 {
1260  TableModel * model;
1261 
1262  model = gnc_table_model_new ();
1263  gnc_entry_ledger_model_new_handlers (model, type);
1264 
1265  return model;
1266 }
utility functions for the GnuCash UI
STRUCTS.
holds information about each virtual cell.
Definition: table-allgui.h:132
TableModel * gnc_entry_ledger_model_new(GncEntryLedgerType type)
Public Interface.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
GncEntry * gnc_entry_ledger_get_entry(GncEntryLedger *ledger, VirtualCellLocation vcell_loc)
Returns the GncEntry at the given location, or NULL if the location is not valid. ...
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void gncEntrySetDocQuantity(GncEntry *entry, gnc_numeric quantity, gboolean is_cn)
Set the internal quantity converting from the quantity as visible on the physical document...
Definition: gncEntry.c:562
time64 gncEntryGetDate(const GncEntry *entry)
DEPRECATED - use gncEntryGetDateGDate() instead! (Because the time-of-day is a misleading extra infor...
Definition: gncEntry.c:913
tax is a number
Definition: gncTaxTable.h:80
char * gnc_get_account_name_for_register(const Account *account)
Get either the full name of the account or the simple name, depending on the configuration parameter ...
Account handling public routines.
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
Definition: table-allgui.c:227
void gnc_date_cell_get_date(DateCell *cell, time64 *time, gboolean warn)
Set a time64 to the value in the DateCell.
void gnc_date_cell_commit(DateCell *cell)
Commits any pending changes to the value of the cell.
char * gnc_print_time64(time64 time, const char *format)
print a time64 as a date string per format
Definition: gnc-date.cpp:368
tax is a percentage
Definition: gncTaxTable.h:81
unsigned int start_primary_color
visible in the GUI
Definition: table-allgui.h:139
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition: gnc-date.h:108
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void gncEntrySetDate(GncEntry *entry, time64 date)
DEPRECATED - use gncEntrySetDateGDate() instead! (Because the time-of-day is a misleading extra infor...
Definition: gncEntry.c:482
The DateCell object implements a date handling cell.
Definition: datecell.h:91
time64 time64CanonicalDayTime(time64 t)
convert a time64 on a certain day (localtime) to the time64 representing midday on that day...
Definition: gnc-date.cpp:402
GncEntry * gnc_entry_ledger_get_blank_entry(GncEntryLedger *ledger)
Exported Functions.
size_t qof_print_date_buff(char *buff, size_t buflen, time64 secs)
Convenience: calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:572
gnc_numeric gncEntryGetDocQuantity(const GncEntry *entry, gboolean is_cn)
Get the quantity as on the physical document.
Definition: gncEntry.c:952
modtime is the internal date of the last modtime See libgnucash/engine/TaxTableBillTermImmutability.txt for an explanation of the following Code that handles refcount, parent, child, invisible and children is identical to that in ::GncBillTerm