GnuCash  5.6-150-g038405b370+
gncTaxTable.c
1 /********************************************************************\
2  * gncTaxTable.c -- the Gnucash Tax Table interface *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA gnu@gnu.org *
20  * *
21 \********************************************************************/
22 
23 /*
24  * Copyright (C) 2002 Derek Atkins
25  * Copyright (C) 2003 Linas Vepstas <linas@linas.org>
26  * Author: Derek Atkins <warlord@MIT.EDU>
27  */
28 
29 #include <config.h>
30 
31 #include <glib.h>
32 #include <qofinstance-p.h>
33 
34 #include "gnc-features.h"
35 #include "gncTaxTableP.h"
36 
38 {
39  QofInstance inst;
40  const char * name;
41  GncTaxTableEntryList* entries;
42  time64 modtime; /* internal date of last modtime */
43 
44  /* See libgnucash/engine/TaxTableBillTermImmutability.txt for an explanation of the following */
45  /* Code that handles this is *identical* to that in gncBillTerm */
46  gint64 refcount;
47  GncTaxTable * parent; /* if non-null, we are an immutable child */
48  GncTaxTable * child; /* if non-null, we have not changed */
49  gboolean invisible;
50  GList * children; /* list of children for disconnection */
51 };
52 
54 {
55  QofInstanceClass parent_class;
56 };
57 
59 {
61  Account * account;
62  GncAmountType type;
63  gnc_numeric amount;
64 };
65 
66 struct _book_info
67 {
68  GList * tables; /* visible tables */
69 };
70 
71 static QofLogModule log_module = GNC_MOD_BUSINESS;
72 
73 /* =============================================================== */
74 /* You must edit the functions in this block in tandem. KEEP THEM IN
75  SYNC! */
76 
77 #define GNC_RETURN_ENUM_AS_STRING(x,s) case (x): return (s);
78 const char *
79 gncAmountTypeToString (GncAmountType type)
80 {
81  switch (type)
82  {
83  GNC_RETURN_ENUM_AS_STRING(GNC_AMT_TYPE_VALUE, "VALUE");
84  GNC_RETURN_ENUM_AS_STRING(GNC_AMT_TYPE_PERCENT, "PERCENT");
85  default:
86  g_warning ("asked to translate unknown amount type %d.\n", type);
87  break;
88  }
89  return(NULL);
90 }
91 
92 const char *
93 gncTaxIncludedTypeToString (GncTaxIncluded type)
94 {
95  switch (type)
96  {
97  GNC_RETURN_ENUM_AS_STRING(GNC_TAXINCLUDED_YES, "YES");
98  GNC_RETURN_ENUM_AS_STRING(GNC_TAXINCLUDED_NO, "NO");
99  GNC_RETURN_ENUM_AS_STRING(GNC_TAXINCLUDED_USEGLOBAL, "USEGLOBAL");
100  default:
101  g_warning ("asked to translate unknown taxincluded type %d.\n", type);
102  break;
103  }
104  return(NULL);
105 }
106 #undef GNC_RETURN_ENUM_AS_STRING
107 #define GNC_RETURN_ON_MATCH(s,x) \
108  if(g_strcmp0((s), (str)) == 0) { *type = x; return(TRUE); }
109 gboolean
110 gncAmountStringToType (const char *str, GncAmountType *type)
111 {
112  GNC_RETURN_ON_MATCH ("VALUE", GNC_AMT_TYPE_VALUE);
113  GNC_RETURN_ON_MATCH ("PERCENT", GNC_AMT_TYPE_PERCENT);
114  g_warning ("asked to translate unknown amount type string %s.\n",
115  str ? str : "(null)");
116 
117  return(FALSE);
118 }
119 
120 gboolean
121 gncTaxIncludedStringToType (const char *str, GncTaxIncluded *type)
122 {
123  GNC_RETURN_ON_MATCH ("YES", GNC_TAXINCLUDED_YES);
124  GNC_RETURN_ON_MATCH ("NO", GNC_TAXINCLUDED_NO);
125  GNC_RETURN_ON_MATCH ("USEGLOBAL", GNC_TAXINCLUDED_USEGLOBAL);
126  g_warning ("asked to translate unknown taxincluded type string %s.\n",
127  str ? str : "(null)");
128 
129  return(FALSE);
130 }
131 #undef GNC_RETURN_ON_MATCH
132 
133 /* =============================================================== */
134 /* Misc inline functions */
135 
136 #define _GNC_MOD_NAME GNC_ID_TAXTABLE
137 
138 #define SET_STR(obj, member, str) { \
139  if (!g_strcmp0 (member, str)) return; \
140  gncTaxTableBeginEdit (obj); \
141  CACHE_REPLACE (member, str); \
142  }
143 
144 static inline void
145 mark_table (GncTaxTable *table)
146 {
147  qof_instance_set_dirty(&table->inst);
148  qof_event_gen (&table->inst, QOF_EVENT_MODIFY, NULL);
149 }
150 
151 static inline void
152 maybe_resort_list (GncTaxTable *table)
153 {
154  struct _book_info *bi;
155 
156  if (table->parent || table->invisible) return;
157  bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
158  bi->tables = g_list_sort (bi->tables, (GCompareFunc)gncTaxTableCompare);
159 }
160 
161 static inline void
162 mod_table (GncTaxTable *table)
163 {
164  table->modtime = gnc_time (NULL);
165 }
166 
167 static inline void addObj (GncTaxTable *table)
168 {
169  struct _book_info *bi;
170  bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
171  bi->tables = g_list_insert_sorted (bi->tables, table,
172  (GCompareFunc)gncTaxTableCompare);
173 }
174 
175 static inline void remObj (GncTaxTable *table)
176 {
177  struct _book_info *bi;
178  bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
179  bi->tables = g_list_remove (bi->tables, table);
180 }
181 
182 static inline void
183 gncTaxTableAddChild (GncTaxTable *table, GncTaxTable *child)
184 {
185  g_return_if_fail(table);
186  g_return_if_fail(child);
187  g_return_if_fail(qof_instance_get_destroying(table) == FALSE);
188 
189  table->children = g_list_prepend(table->children, child);
190 }
191 
192 static inline void
193 gncTaxTableRemoveChild (GncTaxTable *table, const GncTaxTable *child)
194 {
195  g_return_if_fail(table);
196  g_return_if_fail(child);
197 
198  if (qof_instance_get_destroying(table)) return;
199 
200  table->children = g_list_remove(table->children, child);
201 }
202 
203 /* =============================================================== */
204 
205 enum
206 {
207  PROP_0,
208  PROP_NAME, /* Table */
209  PROP_INVISIBLE, /* Table */
210  PROP_REFCOUNT, /* Table */
211 // PROP_PARENT, /* Table */
212 };
213 
214 /* GObject Initialization */
215 G_DEFINE_TYPE(GncTaxTable, gnc_taxtable, QOF_TYPE_INSTANCE)
216 
217 static void
218 gnc_taxtable_init(GncTaxTable* tt)
219 {
220 }
221 
222 static void
223 gnc_taxtable_dispose(GObject *ttp)
224 {
225  G_OBJECT_CLASS(gnc_taxtable_parent_class)->dispose(ttp);
226 }
227 
228 static void
229 gnc_taxtable_finalize(GObject* ttp)
230 {
231  G_OBJECT_CLASS(gnc_taxtable_parent_class)->dispose(ttp);
232 }
233 
234 static void
235 gnc_taxtable_get_property (GObject *object,
236  guint prop_id,
237  GValue *value,
238  GParamSpec *pspec)
239 {
240  GncTaxTable *tt;
241 
242  g_return_if_fail(GNC_IS_TAXTABLE(object));
243 
244  tt = GNC_TAXTABLE(object);
245  switch (prop_id)
246  {
247  case PROP_NAME:
248  g_value_set_string(value, tt->name);
249  break;
250  case PROP_INVISIBLE:
251  g_value_set_boolean(value, tt->invisible);
252  break;
253  case PROP_REFCOUNT:
254  g_value_set_uint64(value, tt->refcount);
255  break;
256  default:
257  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
258  break;
259  }
260 }
261 
262 static void
263 gnc_taxtable_set_property (GObject *object,
264  guint prop_id,
265  const GValue *value,
266  GParamSpec *pspec)
267 {
268  GncTaxTable *tt;
269 
270  g_return_if_fail(GNC_IS_TAXTABLE(object));
271 
272  tt = GNC_TAXTABLE(object);
273  g_assert (qof_instance_get_editlevel(tt));
274 
275  switch (prop_id)
276  {
277  case PROP_NAME:
278  gncTaxTableSetName(tt, g_value_get_string(value));
279  break;
280  case PROP_INVISIBLE:
281  if (g_value_get_boolean(value))
282  {
283  gncTaxTableMakeInvisible(tt);
284  }
285  break;
286  case PROP_REFCOUNT:
287  gncTaxTableSetRefcount(tt, g_value_get_uint64(value));
288  break;
289  default:
290  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
291  break;
292  }
293 }
294 
296 static gchar*
297 impl_get_display_name(const QofInstance* inst)
298 {
299  GncTaxTable* tt;
300 
301  g_return_val_if_fail(inst != NULL, FALSE);
302  g_return_val_if_fail(GNC_IS_TAXTABLE(inst), FALSE);
303 
304  tt = GNC_TAXTABLE(inst);
305  return g_strdup_printf("Tax table %s", tt->name);
306 }
307 
309 static gboolean
310 impl_refers_to_object(const QofInstance* inst, const QofInstance* ref)
311 {
312  GncTaxTable* tt;
313 
314  g_return_val_if_fail(inst != NULL, FALSE);
315  g_return_val_if_fail(GNC_IS_TAXTABLE(inst), FALSE);
316 
317  tt = GNC_TAXTABLE(inst);
318 
319  if (GNC_IS_ACCOUNT(ref))
320  {
321  GList* node;
322 
323  for (node = tt->entries; node != NULL; node = node->next)
324  {
325  GncTaxTableEntry* tte = node->data;
326 
327  if (tte->account == GNC_ACCOUNT(ref))
328  {
329  return TRUE;
330  }
331  }
332  }
333 
334  return FALSE;
335 }
336 
343 static GList*
344 impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
345 {
346  if (!GNC_IS_ACCOUNT(ref))
347  {
348  return NULL;
349  }
350 
352 }
353 
354 static void
355 gnc_taxtable_class_init (GncTaxTableClass *klass)
356 {
357  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
358  QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
359 
360  gobject_class->dispose = gnc_taxtable_dispose;
361  gobject_class->finalize = gnc_taxtable_finalize;
362  gobject_class->set_property = gnc_taxtable_set_property;
363  gobject_class->get_property = gnc_taxtable_get_property;
364 
365  qof_class->get_display_name = impl_get_display_name;
366  qof_class->refers_to_object = impl_refers_to_object;
367  qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
368 
369  g_object_class_install_property
370  (gobject_class,
371  PROP_NAME,
372  g_param_spec_string ("name",
373  "TaxTable Name",
374  "The accountName is an arbitrary string "
375  "assigned by the user. It is intended to "
376  "a short, 10 to 30 character long string "
377  "that is displayed by the GUI as the "
378  "tax table mnemonic.",
379  NULL,
380  G_PARAM_READWRITE));
381 
382  g_object_class_install_property
383  (gobject_class,
384  PROP_INVISIBLE,
385  g_param_spec_boolean ("invisible",
386  "Invisible",
387  "TRUE if the tax table is invisible. FALSE if visible.",
388  FALSE,
389  G_PARAM_READWRITE));
390 
391  g_object_class_install_property
392  (gobject_class,
393  PROP_REFCOUNT,
394  g_param_spec_uint64("ref-count",
395  "Reference count",
396  "The ref-count property contains number of times this tax table "
397  "is referenced.",
398  0, /* min */
399  G_MAXUINT64, /* max */
400  0, /* default */
401  G_PARAM_READWRITE));
402 }
403 
404 /* Create/Destroy Functions */
405 GncTaxTable *
406 gncTaxTableCreate (QofBook *book)
407 {
409  if (!book) return NULL;
410 
411  table = g_object_new (GNC_TYPE_TAXTABLE, NULL);
412  qof_instance_init_data (&table->inst, _GNC_MOD_NAME, book);
413  table->name = CACHE_INSERT ("");
414  addObj (table);
415  qof_event_gen (&table->inst, QOF_EVENT_CREATE, NULL);
416  return table;
417 }
418 
419 void
420 gncTaxTableDestroy (GncTaxTable *table)
421 {
422  if (!table) return;
423  qof_instance_set_destroying(table, TRUE);
424  qof_instance_set_dirty (&table->inst);
425  gncTaxTableCommitEdit (table);
426 }
427 
428 static void
429 gncTaxTableFree (GncTaxTable *table)
430 {
431  GList *list;
432  GncTaxTable *child;
433 
434  if (!table) return;
435 
436  qof_event_gen (&table->inst, QOF_EVENT_DESTROY, NULL);
437  CACHE_REMOVE (table->name);
438  remObj (table);
439 
440  /* destroy the list of entries */
441  for (list = table->entries; list; list = list->next)
442  gncTaxTableEntryDestroy (list->data);
443  g_list_free (table->entries);
444 
446  PERR("free a taxtable without do_free set!");
447 
448  /* disconnect from parent */
449  if (table->parent)
450  gncTaxTableRemoveChild(table->parent, table);
451 
452  /* disconnect from the children */
453  for (list = table->children; list; list = list->next)
454  {
455  child = list->data;
456  gncTaxTableSetParent(child, NULL);
457  }
458  g_list_free(table->children);
459 
460  /* qof_instance_release (&table->inst); */
461  g_object_unref (table);
462 }
463 
464 /* =============================================================== */
465 
466 GncTaxTableEntry * gncTaxTableEntryCreate (void)
467 {
468  GncTaxTableEntry *entry;
469  entry = g_new0 (GncTaxTableEntry, 1);
470  entry->amount = gnc_numeric_zero ();
471  return entry;
472 }
473 
474 void gncTaxTableEntryDestroy (GncTaxTableEntry *entry)
475 {
476  if (!entry) return;
477  g_free (entry);
478 }
479 
480 /* =============================================================== */
481 /* Set Functions */
482 
483 void gncTaxTableSetName (GncTaxTable *table, const char *name)
484 {
485  if (!table || !name) return;
486  SET_STR (table, table->name, name);
487  mark_table (table);
488  maybe_resort_list (table);
489  gncTaxTableCommitEdit (table);
490 }
491 
492 void gncTaxTableSetParent (GncTaxTable *table, GncTaxTable *parent)
493 {
494  if (!table) return;
495  gncTaxTableBeginEdit (table);
496  if (table->parent)
497  gncTaxTableRemoveChild(table->parent, table);
498  table->parent = parent;
499  if (parent)
500  gncTaxTableAddChild(parent, table);
501  table->refcount = 0;
502  gncTaxTableMakeInvisible (table);
503  mark_table (table);
504  gncTaxTableCommitEdit (table);
505 }
506 
507 void gncTaxTableSetChild (GncTaxTable *table, GncTaxTable *child)
508 {
509  if (!table) return;
510  gncTaxTableBeginEdit (table);
511  table->child = child;
512  mark_table (table);
513  gncTaxTableCommitEdit (table);
514 }
515 
516 void gncTaxTableIncRef (GncTaxTable *table)
517 {
518  if (!table) return;
519  if (table->parent || table->invisible) return; /* children dont need refcounts */
520  gncTaxTableBeginEdit (table);
521  table->refcount++;
522  mark_table (table);
523  gncTaxTableCommitEdit (table);
524 }
525 
526 void gncTaxTableDecRef (GncTaxTable *table)
527 {
528  if (!table) return;
529  if (table->parent || table->invisible) return; /* children dont need refcounts */
530  g_return_if_fail (table->refcount > 0);
531  gncTaxTableBeginEdit (table);
532  table->refcount--;
533  mark_table (table);
534  gncTaxTableCommitEdit (table);
535 }
536 
537 void gncTaxTableSetRefcount (GncTaxTable *table, gint64 refcount)
538 {
539  if (!table) return;
540  g_return_if_fail (refcount >= 0);
541  gncTaxTableBeginEdit (table);
542  table->refcount = refcount;
543  mark_table (table);
544  gncTaxTableCommitEdit (table);
545 }
546 
547 void gncTaxTableMakeInvisible (GncTaxTable *table)
548 {
549  struct _book_info *bi;
550  if (!table) return;
551  gncTaxTableBeginEdit (table);
552  table->invisible = TRUE;
553  bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
554  bi->tables = g_list_remove (bi->tables, table);
555  gncTaxTableCommitEdit (table);
556 }
557 
558 void gncTaxTableEntrySetAccount (GncTaxTableEntry *entry, Account *account)
559 {
560  if (!entry || !account) return;
561  if (entry->account == account) return;
562  entry->account = account;
563  if (entry->table)
564  {
565  mark_table (entry->table);
566  mod_table (entry->table);
567  }
568 }
569 
570 void gncTaxTableEntrySetType (GncTaxTableEntry *entry, GncAmountType type)
571 {
572  if (!entry) return;
573  if (entry->type == type) return;
574  entry->type = type;
575  if (entry->table)
576  {
577  mark_table (entry->table);
578  mod_table (entry->table);
579  }
580 }
581 
582 void gncTaxTableEntrySetAmount (GncTaxTableEntry *entry, gnc_numeric amount)
583 {
584  if (!entry) return;
585  if (gnc_numeric_eq (entry->amount, amount)) return;
586  entry->amount = amount;
587  if (entry->table)
588  {
589  mark_table (entry->table);
590  mod_table (entry->table);
591  }
592 }
593 
594 void gncTaxTableAddEntry (GncTaxTable *table, GncTaxTableEntry *entry)
595 {
596  if (!table || !entry) return;
597  if (entry->table == table) return; /* already mine */
598 
599  gncTaxTableBeginEdit (table);
600  if (entry->table)
601  gncTaxTableRemoveEntry (entry->table, entry);
602 
603  entry->table = table;
604  table->entries = g_list_insert_sorted (table->entries, entry,
605  (GCompareFunc)gncTaxTableEntryCompare);
606  mark_table (table);
607  mod_table (table);
608  gncTaxTableCommitEdit (table);
609 }
610 
611 void gncTaxTableRemoveEntry (GncTaxTable *table, GncTaxTableEntry *entry)
612 {
613  if (!table || !entry) return;
614  gncTaxTableBeginEdit (table);
615  entry->table = NULL;
616  table->entries = g_list_remove (table->entries, entry);
617  mark_table (table);
618  mod_table (table);
619  gncTaxTableCommitEdit (table);
620 }
621 
622 void gncTaxTableChanged (GncTaxTable *table)
623 {
624  if (!table) return;
625  gncTaxTableBeginEdit (table);
626  table->child = NULL;
627  gncTaxTableCommitEdit (table);
628 }
629 
630 /* =============================================================== */
631 
632 void gncTaxTableBeginEdit (GncTaxTable *table)
633 {
634  qof_begin_edit(&table->inst);
635 }
636 
637 static void gncTaxTableOnError (QofInstance *inst, QofBackendError errcode)
638 {
639  PERR("TaxTable QofBackend Failure: %d", errcode);
640  gnc_engine_signal_commit_error( errcode );
641 }
642 
643 static void gncTaxTableOnDone (QofInstance *inst) {}
644 
645 static void table_free (QofInstance *inst)
646 {
647  GncTaxTable *table = (GncTaxTable *) inst;
648  gncTaxTableFree (table);
649 }
650 
651 void gncTaxTableCommitEdit (GncTaxTable *table)
652 {
653  /* GnuCash 2.6.3 and earlier didn't handle taxtable kvp's... */
654  if (qof_instance_has_kvp (QOF_INSTANCE (table)))
656  GNC_FEATURE_KVP_EXTRA_DATA);
657 
658  if (!qof_commit_edit (QOF_INSTANCE(table))) return;
659  qof_commit_edit_part2 (&table->inst, gncTaxTableOnError,
660  gncTaxTableOnDone, table_free);
661 }
662 
663 
664 /* =============================================================== */
665 /* Get Functions */
666 
667 GncTaxTable *gncTaxTableLookupByName (QofBook *book, const char *name)
668 {
669  GList *list = gncTaxTableGetTables (book);
670 
671  for ( ; list; list = list->next)
672  {
673  GncTaxTable *table = list->data;
674  if (!g_strcmp0 (table->name, name))
675  return list->data;
676  }
677  return NULL;
678 }
679 
681 gncTaxTableGetDefault (QofBook *book, GncOwnerType type)
682 {
683  GSList *path = NULL;
684  const GncGUID *guid = NULL;
685  const char *vendor = "Default Vendor TaxTable";
686  const char *customer = "Default Customer TaxTable";
687  const char *section = "Business";
688 
689  g_return_val_if_fail (book != NULL, NULL);
690  g_return_val_if_fail (type == GNC_OWNER_CUSTOMER || \
691  type == GNC_OWNER_VENDOR, NULL);
692  path = g_slist_prepend (path, type == GNC_OWNER_CUSTOMER ? (void*)customer : (void*)vendor);
693  path = g_slist_prepend (path, (void*)section);
694 
695  guid = qof_book_get_guid_option (book, path);
696  g_slist_free (path);
697 
698  return gncTaxTableLookup (book, guid);
699 }
700 
701 GncTaxTableList * gncTaxTableGetTables (QofBook *book)
702 {
703  struct _book_info *bi;
704  if (!book) return NULL;
705 
706  bi = qof_book_get_data (book, _GNC_MOD_NAME);
707  return bi ? bi->tables : NULL;
708 }
709 
710 const char *gncTaxTableGetName (const GncTaxTable *table)
711 {
712  if (!table) return NULL;
713  return table->name;
714 }
715 
716 static GncTaxTableEntry *gncTaxTableEntryCopy (const GncTaxTableEntry *entry)
717 {
718  GncTaxTableEntry *e;
719  if (!entry) return NULL;
720 
721  e = gncTaxTableEntryCreate ();
722  gncTaxTableEntrySetAccount (e, entry->account);
723  gncTaxTableEntrySetType (e, entry->type);
724  gncTaxTableEntrySetAmount (e, entry->amount);
725 
726  return e;
727 }
728 
729 static GncTaxTable *gncTaxTableCopy (const GncTaxTable *table)
730 {
731  GncTaxTable *t;
732  GList *list;
733 
734  if (!table) return NULL;
735  t = gncTaxTableCreate (qof_instance_get_book(table));
736  gncTaxTableSetName (t, table->name);
737  for (list = table->entries; list; list = list->next)
738  {
739  GncTaxTableEntry *entry, *e;
740  entry = list->data;
741  e = gncTaxTableEntryCopy (entry);
742  /* Clang static analyzer thinks we're leaking e, but we're not.
743  * We're transferring it to table. */
744  gncTaxTableAddEntry (t, e);
745  }
746  return t;
747 }
748 
749 GncTaxTable *gncTaxTableReturnChild (GncTaxTable *table, gboolean make_new)
750 {
751  GncTaxTable *child = NULL;
752 
753  if (!table) return NULL;
754  if (table->child) return table->child;
755  if (table->parent || table->invisible) return table;
756  if (make_new)
757  {
758  child = gncTaxTableCopy (table);
759  gncTaxTableSetChild (table, child);
760  gncTaxTableSetParent (child, table);
761  }
762  return child;
763 }
764 
765 GncTaxTable *gncTaxTableGetParent (const GncTaxTable *table)
766 {
767  if (!table) return NULL;
768  return table->parent;
769 }
770 
771 GncTaxTableEntryList* gncTaxTableGetEntries (const GncTaxTable *table)
772 {
773  if (!table) return NULL;
774  return table->entries;
775 }
776 
777 gint64 gncTaxTableGetRefcount (const GncTaxTable *table)
778 {
779  if (!table) return 0;
780  return table->refcount;
781 }
782 
783 time64 gncTaxTableLastModifiedSecs (const GncTaxTable *table)
784 {
785  if (!table) return 0;
786  return table->modtime;
787 }
788 
789 gboolean gncTaxTableGetInvisible (const GncTaxTable *table)
790 {
791  if (!table) return FALSE;
792  return table->invisible;
793 }
794 
795 Account * gncTaxTableEntryGetAccount (const GncTaxTableEntry *entry)
796 {
797  if (!entry) return NULL;
798  return entry->account;
799 }
800 
801 GncAmountType gncTaxTableEntryGetType (const GncTaxTableEntry *entry)
802 {
803  if (!entry) return 0;
804  return entry->type;
805 }
806 
807 gnc_numeric gncTaxTableEntryGetAmount (const GncTaxTableEntry *entry)
808 {
809  if (!entry) return gnc_numeric_zero();
810  return entry->amount;
811 }
812 
813 /* This is a semi-private function (meaning that it's not declared in
814  * the header) used for SQL Backend testing. */
815 GncTaxTable* gncTaxTableEntryGetTable( const GncTaxTableEntry* entry )
816 {
817  if (!entry) return NULL;
818  return entry->table;
819 }
820 
821 int gncTaxTableEntryCompare (const GncTaxTableEntry *a, const GncTaxTableEntry *b)
822 {
823  char *name_a, *name_b;
824  int retval;
825 
826  if (!a && !b) return 0;
827  if (!a) return -1;
828  if (!b) return 1;
829 
830  name_a = gnc_account_get_full_name (a->account);
831  name_b = gnc_account_get_full_name (b->account);
832  retval = g_strcmp0(name_a, name_b);
833  g_free(name_a);
834  g_free(name_b);
835 
836  if (retval)
837  return retval;
838 
839  return gnc_numeric_compare (a->amount, b->amount);
840 }
841 
842 int gncTaxTableCompare (const GncTaxTable *a, const GncTaxTable *b)
843 {
844  if (!a && !b) return 0;
845  if (!a) return -1;
846  if (!b) return 1;
847  return g_strcmp0 (a->name, b->name);
848 }
849 
850 gboolean gncTaxTableEntryEqual(const GncTaxTableEntry *a, const GncTaxTableEntry *b)
851 {
852  if (a == NULL && b == NULL) return TRUE;
853  if (a == NULL || b == NULL) return FALSE;
854 
855  if (!xaccAccountEqual(a->account, b->account, TRUE))
856  {
857  PWARN("accounts differ");
858  return FALSE;
859  }
860 
861  if (a->type != b->type)
862  {
863  PWARN("types differ");
864  return FALSE;
865  }
866 
867  if (!gnc_numeric_equal(a->amount, b->amount))
868  {
869  PWARN("amounts differ");
870  return FALSE;
871  }
872 
873  return TRUE;
874 }
875 
876 gboolean gncTaxTableEqual(const GncTaxTable *a, const GncTaxTable *b)
877 {
878  if (a == NULL && b == NULL) return TRUE;
879  if (a == NULL || b == NULL) return FALSE;
880 
881  g_return_val_if_fail(GNC_IS_TAXTABLE(a), FALSE);
882  g_return_val_if_fail(GNC_IS_TAXTABLE(b), FALSE);
883 
884  if (g_strcmp0(a->name, b->name) != 0)
885  {
886  PWARN("Names differ: %s vs %s", a->name, b->name);
887  return FALSE;
888  }
889 
890  if (a->invisible != b->invisible)
891  {
892  PWARN("invisible flags differ");
893  return FALSE;
894  }
895 
896  if ((a->entries != NULL) != (b->entries != NULL))
897  {
898  PWARN("only one has entries");
899  return FALSE;
900  }
901 
902  if (a->entries != NULL && b->entries != NULL)
903  {
904  GncTaxTableEntryList* a_node;
905  GncTaxTableEntryList* b_node;
906 
907  for (a_node = a->entries, b_node = b->entries;
908  a_node != NULL && b_node != NULL;
909  a_node = a_node->next, b_node = b_node->next)
910  {
911  if (!gncTaxTableEntryEqual((GncTaxTableEntry*)a_node->data,
912  (GncTaxTableEntry*)b_node->data))
913  {
914  PWARN("entries differ");
915  return FALSE;
916  }
917  }
918 
919  if (a_node != NULL || b_node != NULL)
920  {
921  PWARN("Unequal number of entries");
922  return FALSE;
923  }
924  }
925 
926 #if 0
927  /* See libgnucash/engine/TaxTableBillTermImmutability.txt for an explanation of the following */
928  /* Code that handles this is *identical* to that in gncBillTerm */
929  gint64 refcount;
930  GncTaxTable * parent; /* if non-null, we are an immutable child */
931  GncTaxTable * child; /* if non-null, we have not changed */
932  GList * children; /* list of children for disconnection */
933 #endif
934 
935  return TRUE;
936 }
937 
938 /*
939  * This will add value to the account-value for acc, creating a new
940  * list object if necessary
941  */
942 GList *gncAccountValueAdd (GList *list, Account *acc, gnc_numeric value)
943 {
944  GList *li;
945  GncAccountValue *res = NULL;
946 
947  g_return_val_if_fail (acc, list);
948  g_return_val_if_fail (gnc_numeric_check (value) == GNC_ERROR_OK, list);
949 
950  /* Try to find the account in the list */
951  for (li = list; li; li = li->next)
952  {
953  res = li->data;
954  if (res->account == acc)
955  {
956  res->value = gnc_numeric_add (res->value, value, GNC_DENOM_AUTO,
958  return list;
959  }
960  }
961  /* Nope, didn't find it. */
962 
963  res = g_new0 (GncAccountValue, 1);
964  res->account = acc;
965  res->value = value;
966  return g_list_prepend (list, res);
967 }
968 
969 /* Merge l2 into l1. l2 is not touched. */
970 GList *gncAccountValueAddList (GList *l1, GList *l2)
971 {
972  GList *li;
973 
974  for (li = l2; li; li = li->next )
975  {
976  GncAccountValue *val = li->data;
977  l1 = gncAccountValueAdd (l1, val->account, val->value);
978  }
979 
980  return l1;
981 }
982 
983 /* return the total for this list */
984 gnc_numeric gncAccountValueTotal (GList *list)
985 {
986  gnc_numeric total = gnc_numeric_zero ();
987 
988  for ( ; list ; list = list->next)
989  {
990  GncAccountValue *val = list->data;
992  }
993  return total;
994 }
995 
996 /* Destroy a list of accountvalues */
997 void gncAccountValueDestroy (GList *list)
998 {
999  GList *node;
1000  for ( node = list; node ; node = node->next)
1001  g_free (node->data);
1002 
1003  g_list_free (list);
1004 }
1005 
1006 /* Package-Private functions */
1007 
1008 static void _gncTaxTableCreate (QofBook *book)
1009 {
1010  struct _book_info *bi;
1011 
1012  if (!book) return;
1013 
1014  bi = g_new0 (struct _book_info, 1);
1015  qof_book_set_data (book, _GNC_MOD_NAME, bi);
1016 }
1017 
1018 static void
1019 destroy_taxtable_on_book_close (QofInstance *ent, gpointer data)
1020 {
1021  GncTaxTable *table = GNC_TAXTABLE(ent);
1022 
1023  gncTaxTableBeginEdit (table);
1024  gncTaxTableDestroy (table);
1025 }
1026 
1027 static void _gncTaxTableDestroy (QofBook *book)
1028 {
1029  struct _book_info *bi;
1030  QofCollection *col;
1031 
1032  if (!book) return;
1033 
1034  bi = qof_book_get_data (book, _GNC_MOD_NAME);
1035 
1036  col = qof_book_get_collection (book, GNC_ID_TAXTABLE);
1037  qof_collection_foreach (col, destroy_taxtable_on_book_close, NULL);
1038 
1039  g_list_free (bi->tables);
1040  g_free (bi);
1041 }
1042 
1043 static QofObject gncTaxTableDesc =
1044 {
1045  DI(.interface_version = ) QOF_OBJECT_VERSION,
1046  DI(.e_type = ) _GNC_MOD_NAME,
1047  DI(.type_label = ) "Tax Table",
1048  DI(.create = ) (gpointer)gncTaxTableCreate,
1049  DI(.book_begin = ) _gncTaxTableCreate,
1050  DI(.book_end = ) _gncTaxTableDestroy,
1051  DI(.is_dirty = ) qof_collection_is_dirty,
1052  DI(.mark_clean = ) qof_collection_mark_clean,
1053  DI(.foreach = ) qof_collection_foreach,
1054  DI(.printable = ) NULL,
1055  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
1056 };
1057 
1058 gboolean gncTaxTableRegister (void)
1059 {
1060  static QofParam params[] =
1061  {
1062  { GNC_TT_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncTaxTableGetName, (QofSetterFunc)gncTaxTableSetName },
1063  { GNC_TT_REFCOUNT, QOF_TYPE_INT64, (QofAccessFunc)gncTaxTableGetRefcount, (QofSetterFunc)gncTaxTableSetRefcount },
1064  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
1065  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
1066  { NULL },
1067  };
1068 
1069  qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncTaxTableCompare, params);
1070 
1071  return qof_object_register (&gncTaxTableDesc);
1072 }
1073 
1074 /* need a QOF tax table entry object */
1075 //gncTaxTableEntrySetType_q int32
1076 //gint gncTaxTableEntryGetType_q (GncTaxTableEntry *entry);
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
tax is not included
Definition: gncTaxTable.h:88
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:255
GncTaxIncluded
How to interpret the TaxIncluded.
Definition: gncTaxTable.h:85
#define GNC_TT_NAME
QOF parameter definitions.
Definition: gncTaxTable.h:210
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
STRUCTS.
GList * qof_instance_get_referring_object_list_from_collection(const QofCollection *coll, const QofInstance *ref)
Returns a list of objects from the collection which refer to the specific object. ...
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition: qofclass.cpp:86
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
tax is included
Definition: gncTaxTable.h:87
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
gnc_numeric gncAccountValueTotal(GList *list)
return the total for this list
Definition: gncTaxTable.c:984
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:223
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:63
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:108
use the global setting
Definition: gncTaxTable.h:89
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:185
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
tax is a number
Definition: gncTaxTable.h:80
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3257
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:195
tax is a percentage
Definition: gncTaxTable.h:81
void qof_book_set_data(QofBook *book, const gchar *key, gpointer data)
The qof_book_set_data() allows arbitrary pointers to structs to be stored in QofBook.
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:178
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:261
void gncAccountValueDestroy(GList *list)
Destroy a list of accountvalues.
Definition: gncTaxTable.c:997
gboolean xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
Compare two accounts for equality - this is a deep compare.
Definition: Account.cpp:1651
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and ...
GList * gncAccountValueAddList(GList *l1, GList *l2)
Merge l2 into l1.
Definition: gncTaxTable.c:970
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:521
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:299
GList * gncAccountValueAdd(GList *list, Account *acc, gnc_numeric value)
This will add value to the account-value for acc, creating a new list object if necessary.
Definition: gncTaxTable.c:942
gboolean qof_instance_has_kvp(QofInstance *inst)
Report whether a QofInstance has anything stored in KVP.
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
No error.
Definition: gnc-numeric.h:223
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
The type used to store guids in C.
Definition: guid.h:75
gpointer qof_book_get_data(const QofBook *book, const gchar *key)
Retrieves arbitrary pointers to structs stored by qof_book_set_data.
GncAmountType
How to interpret the amount.
Definition: gncTaxTable.h:78
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
Utility functions for file access.