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
37 struct _gncTaxTable
38 {
39 QofInstance inst;
40 const char * name;
41 GncTaxTableEntryList* entries;
42 time64 modtime; /* internal date of last modtime */
43
44 /* See src/doc/business.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
53 struct _gncTaxTableClass
54 {
55 QofInstanceClass parent_class;
56 };
57
58 struct _gncTaxTableEntry
59 {
60 GncTaxTable * table;
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 *
gncAmountTypeToString(GncAmountType type)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 *
gncTaxIncludedTypeToString(GncTaxIncluded type)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
gncAmountStringToType(const char * str,GncAmountType * type)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
gncTaxIncludedStringToType(const char * str,GncTaxIncluded * type)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
mark_table(GncTaxTable * table)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
maybe_resort_list(GncTaxTable * table)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
mod_table(GncTaxTable * table)162 mod_table (GncTaxTable *table)
163 {
164 table->modtime = gnc_time (NULL);
165 }
166
addObj(GncTaxTable * table)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
remObj(GncTaxTable * table)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
gncTaxTableAddChild(GncTaxTable * table,GncTaxTable * child)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
gncTaxTableRemoveChild(GncTaxTable * table,const GncTaxTable * child)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
gnc_taxtable_init(GncTaxTable * tt)218 gnc_taxtable_init(GncTaxTable* tt)
219 {
220 }
221
222 static void
gnc_taxtable_dispose(GObject * ttp)223 gnc_taxtable_dispose(GObject *ttp)
224 {
225 G_OBJECT_CLASS(gnc_taxtable_parent_class)->dispose(ttp);
226 }
227
228 static void
gnc_taxtable_finalize(GObject * ttp)229 gnc_taxtable_finalize(GObject* ttp)
230 {
231 G_OBJECT_CLASS(gnc_taxtable_parent_class)->dispose(ttp);
232 }
233
234 static void
gnc_taxtable_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)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
gnc_taxtable_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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
295 /** Return displayable name */
296 static gchar*
impl_get_display_name(const QofInstance * inst)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
308 /** Does this object refer to a specific object */
309 static gboolean
impl_refers_to_object(const QofInstance * inst,const QofInstance * ref)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
337 /** Returns a list of my type of object which refers to an object. For example, when called as
338 qof_instance_get_typed_referring_object_list(taxtable, account);
339 it will return the list of taxtables which refer to a specific account. The result should be the
340 same regardless of which taxtable object is used. The list must be freed by the caller but the
341 objects on the list must not.
342 */
343 static GList*
impl_get_typed_referring_object_list(const QofInstance * inst,const QofInstance * ref)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
351 return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
352 }
353
354 static void
gnc_taxtable_class_init(GncTaxTableClass * klass)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 *
gncTaxTableCreate(QofBook * book)406 gncTaxTableCreate (QofBook *book)
407 {
408 GncTaxTable *table;
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
gncTaxTableDestroy(GncTaxTable * table)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
gncTaxTableFree(GncTaxTable * table)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
445 if (!qof_instance_get_destroying(table))
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
gncTaxTableEntryCreate(void)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
gncTaxTableEntryDestroy(GncTaxTableEntry * entry)474 void gncTaxTableEntryDestroy (GncTaxTableEntry *entry)
475 {
476 if (!entry) return;
477 g_free (entry);
478 }
479
480 /* =============================================================== */
481 /* Set Functions */
482
gncTaxTableSetName(GncTaxTable * table,const char * name)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
gncTaxTableSetParent(GncTaxTable * table,GncTaxTable * parent)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
gncTaxTableSetChild(GncTaxTable * table,GncTaxTable * child)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
gncTaxTableIncRef(GncTaxTable * table)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
gncTaxTableDecRef(GncTaxTable * table)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
gncTaxTableSetRefcount(GncTaxTable * table,gint64 refcount)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
gncTaxTableMakeInvisible(GncTaxTable * table)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
gncTaxTableEntrySetAccount(GncTaxTableEntry * entry,Account * account)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
gncTaxTableEntrySetType(GncTaxTableEntry * entry,GncAmountType type)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
gncTaxTableEntrySetAmount(GncTaxTableEntry * entry,gnc_numeric amount)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
gncTaxTableAddEntry(GncTaxTable * table,GncTaxTableEntry * entry)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
gncTaxTableRemoveEntry(GncTaxTable * table,GncTaxTableEntry * entry)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
gncTaxTableChanged(GncTaxTable * table)622 void gncTaxTableChanged (GncTaxTable *table)
623 {
624 if (!table) return;
625 gncTaxTableBeginEdit (table);
626 table->child = NULL;
627 gncTaxTableCommitEdit (table);
628 }
629
630 /* =============================================================== */
631
gncTaxTableBeginEdit(GncTaxTable * table)632 void gncTaxTableBeginEdit (GncTaxTable *table)
633 {
634 qof_begin_edit(&table->inst);
635 }
636
gncTaxTableOnError(QofInstance * inst,QofBackendError errcode)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
gncTaxTableOnDone(QofInstance * inst)643 static void gncTaxTableOnDone (QofInstance *inst) {}
644
table_free(QofInstance * inst)645 static void table_free (QofInstance *inst)
646 {
647 GncTaxTable *table = (GncTaxTable *) inst;
648 gncTaxTableFree (table);
649 }
650
gncTaxTableCommitEdit(GncTaxTable * table)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)))
655 gnc_features_set_used (qof_instance_get_book (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
gncTaxTableLookupByName(QofBook * book,const char * name)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
680 GncTaxTable*
gncTaxTableGetDefault(QofBook * book,GncOwnerType type)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
gncTaxTableGetTables(QofBook * book)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
gncTaxTableGetName(const GncTaxTable * table)710 const char *gncTaxTableGetName (const GncTaxTable *table)
711 {
712 if (!table) return NULL;
713 return table->name;
714 }
715
gncTaxTableEntryCopy(const GncTaxTableEntry * entry)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
gncTaxTableCopy(const GncTaxTable * table)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
gncTaxTableReturnChild(GncTaxTable * table,gboolean make_new)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
gncTaxTableGetParent(const GncTaxTable * table)765 GncTaxTable *gncTaxTableGetParent (const GncTaxTable *table)
766 {
767 if (!table) return NULL;
768 return table->parent;
769 }
770
gncTaxTableGetEntries(const GncTaxTable * table)771 GncTaxTableEntryList* gncTaxTableGetEntries (const GncTaxTable *table)
772 {
773 if (!table) return NULL;
774 return table->entries;
775 }
776
gncTaxTableGetRefcount(const GncTaxTable * table)777 gint64 gncTaxTableGetRefcount (const GncTaxTable *table)
778 {
779 if (!table) return 0;
780 return table->refcount;
781 }
782
gncTaxTableLastModifiedSecs(const GncTaxTable * table)783 time64 gncTaxTableLastModifiedSecs (const GncTaxTable *table)
784 {
785 if (!table) return 0;
786 return table->modtime;
787 }
788
gncTaxTableGetInvisible(const GncTaxTable * table)789 gboolean gncTaxTableGetInvisible (const GncTaxTable *table)
790 {
791 if (!table) return FALSE;
792 return table->invisible;
793 }
794
gncTaxTableEntryGetAccount(const GncTaxTableEntry * entry)795 Account * gncTaxTableEntryGetAccount (const GncTaxTableEntry *entry)
796 {
797 if (!entry) return NULL;
798 return entry->account;
799 }
800
gncTaxTableEntryGetType(const GncTaxTableEntry * entry)801 GncAmountType gncTaxTableEntryGetType (const GncTaxTableEntry *entry)
802 {
803 if (!entry) return 0;
804 return entry->type;
805 }
806
gncTaxTableEntryGetAmount(const GncTaxTableEntry * entry)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. */
gncTaxTableEntryGetTable(const GncTaxTableEntry * entry)815 GncTaxTable* gncTaxTableEntryGetTable( const GncTaxTableEntry* entry )
816 {
817 if (!entry) return NULL;
818 return entry->table;
819 }
820
gncTaxTableEntryCompare(const GncTaxTableEntry * a,const GncTaxTableEntry * b)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
gncTaxTableCompare(const GncTaxTable * a,const GncTaxTable * b)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
gncTaxTableEntryEqual(const GncTaxTableEntry * a,const GncTaxTableEntry * b)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
gncTaxTableEqual(const GncTaxTable * a,const GncTaxTable * b)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 src/doc/business.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 */
gncAccountValueAdd(GList * list,Account * acc,gnc_numeric value)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,
957 GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND_HALF_UP);
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. */
gncAccountValueAddList(GList * l1,GList * l2)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 */
gncAccountValueTotal(GList * 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;
991 total = gnc_numeric_add (total, val->value, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND_HALF_UP);
992 }
993 return total;
994 }
995
996 /* Destroy a list of accountvalues */
gncAccountValueDestroy(GList * list)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
_gncTaxTableCreate(QofBook * book)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
_gncTaxTableDestroy(QofBook * book)1018 static void _gncTaxTableDestroy (QofBook *book)
1019 {
1020 struct _book_info *bi;
1021
1022 if (!book) return;
1023
1024 bi = qof_book_get_data (book, _GNC_MOD_NAME);
1025
1026 g_list_free (bi->tables);
1027 g_free (bi);
1028 }
1029
1030 static QofObject gncTaxTableDesc =
1031 {
1032 DI(.interface_version = ) QOF_OBJECT_VERSION,
1033 DI(.e_type = ) _GNC_MOD_NAME,
1034 DI(.type_label = ) "Tax Table",
1035 DI(.create = ) (gpointer)gncTaxTableCreate,
1036 DI(.book_begin = ) _gncTaxTableCreate,
1037 DI(.book_end = ) _gncTaxTableDestroy,
1038 DI(.is_dirty = ) qof_collection_is_dirty,
1039 DI(.mark_clean = ) qof_collection_mark_clean,
1040 DI(.foreach = ) qof_collection_foreach,
1041 DI(.printable = ) NULL,
1042 DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
1043 };
1044
gncTaxTableRegister(void)1045 gboolean gncTaxTableRegister (void)
1046 {
1047 static QofParam params[] =
1048 {
1049 { GNC_TT_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncTaxTableGetName, (QofSetterFunc)gncTaxTableSetName },
1050 { GNC_TT_REFCOUNT, QOF_TYPE_INT64, (QofAccessFunc)gncTaxTableGetRefcount, (QofSetterFunc)gncTaxTableSetRefcount },
1051 { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
1052 { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
1053 { NULL },
1054 };
1055
1056 qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncTaxTableCompare, params);
1057
1058 return qof_object_register (&gncTaxTableDesc);
1059 }
1060
1061 /* need a QOF tax table entry object */
1062 //gncTaxTableEntrySetType_q int32
1063 //gint gncTaxTableEntryGetType_q (GncTaxTableEntry *entry);
1064