Line data Source code
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 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 :
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 *
79 41 : gncAmountTypeToString (GncAmountType type)
80 : {
81 41 : switch (type)
82 : {
83 20 : GNC_RETURN_ENUM_AS_STRING(GNC_AMT_TYPE_VALUE, "VALUE");
84 21 : GNC_RETURN_ENUM_AS_STRING(GNC_AMT_TYPE_PERCENT, "PERCENT");
85 0 : default:
86 0 : g_warning ("asked to translate unknown amount type %d.\n", type);
87 0 : break;
88 : }
89 0 : return(NULL);
90 : }
91 :
92 : const char *
93 3 : gncTaxIncludedTypeToString (GncTaxIncluded type)
94 : {
95 3 : switch (type)
96 : {
97 0 : GNC_RETURN_ENUM_AS_STRING(GNC_TAXINCLUDED_YES, "YES");
98 0 : GNC_RETURN_ENUM_AS_STRING(GNC_TAXINCLUDED_NO, "NO");
99 3 : GNC_RETURN_ENUM_AS_STRING(GNC_TAXINCLUDED_USEGLOBAL, "USEGLOBAL");
100 0 : default:
101 0 : g_warning ("asked to translate unknown taxincluded type %d.\n", type);
102 0 : break;
103 : }
104 0 : 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 3 : gncAmountStringToType (const char *str, GncAmountType *type)
111 : {
112 3 : GNC_RETURN_ON_MATCH ("VALUE", GNC_AMT_TYPE_VALUE);
113 3 : GNC_RETURN_ON_MATCH ("PERCENT", GNC_AMT_TYPE_PERCENT);
114 0 : g_warning ("asked to translate unknown amount type string %s.\n",
115 : str ? str : "(null)");
116 :
117 0 : return(FALSE);
118 : }
119 :
120 : gboolean
121 5 : gncTaxIncludedStringToType (const char *str, GncTaxIncluded *type)
122 : {
123 5 : GNC_RETURN_ON_MATCH ("YES", GNC_TAXINCLUDED_YES);
124 5 : GNC_RETURN_ON_MATCH ("NO", GNC_TAXINCLUDED_NO);
125 5 : GNC_RETURN_ON_MATCH ("USEGLOBAL", GNC_TAXINCLUDED_USEGLOBAL);
126 0 : g_warning ("asked to translate unknown taxincluded type string %s.\n",
127 : str ? str : "(null)");
128 :
129 0 : 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 192 : mark_table (GncTaxTable *table)
146 : {
147 192 : qof_instance_set_dirty(&table->inst);
148 192 : qof_event_gen (&table->inst, QOF_EVENT_MODIFY, NULL);
149 192 : }
150 :
151 : static inline void
152 29 : maybe_resort_list (GncTaxTable *table)
153 : {
154 : struct _book_info *bi;
155 :
156 29 : if (table->parent || table->invisible) return;
157 29 : bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
158 29 : bi->tables = g_list_sort (bi->tables, (GCompareFunc)gncTaxTableCompare);
159 : }
160 :
161 : static inline void
162 38 : mod_table (GncTaxTable *table)
163 : {
164 38 : table->modtime = gnc_time (NULL);
165 38 : }
166 :
167 29 : static inline void addObj (GncTaxTable *table)
168 : {
169 : struct _book_info *bi;
170 29 : bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
171 29 : bi->tables = g_list_insert_sorted (bi->tables, table,
172 : (GCompareFunc)gncTaxTableCompare);
173 29 : }
174 :
175 7 : static inline void remObj (GncTaxTable *table)
176 : {
177 : struct _book_info *bi;
178 7 : bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
179 7 : bi->tables = g_list_remove (bi->tables, table);
180 7 : }
181 :
182 : static inline void
183 5 : gncTaxTableAddChild (GncTaxTable *table, GncTaxTable *child)
184 : {
185 5 : g_return_if_fail(table);
186 5 : g_return_if_fail(child);
187 5 : g_return_if_fail(qof_instance_get_destroying(table) == FALSE);
188 :
189 5 : table->children = g_list_prepend(table->children, child);
190 : }
191 :
192 : static inline void
193 0 : gncTaxTableRemoveChild (GncTaxTable *table, const GncTaxTable *child)
194 : {
195 0 : g_return_if_fail(table);
196 0 : g_return_if_fail(child);
197 :
198 0 : if (qof_instance_get_destroying(table)) return;
199 :
200 0 : 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 96 : G_DEFINE_TYPE(GncTaxTable, gnc_taxtable, QOF_TYPE_INSTANCE)
216 :
217 : static void
218 29 : gnc_taxtable_init(GncTaxTable* tt)
219 : {
220 29 : }
221 :
222 : static void
223 7 : gnc_taxtable_dispose(GObject *ttp)
224 : {
225 7 : G_OBJECT_CLASS(gnc_taxtable_parent_class)->dispose(ttp);
226 7 : }
227 :
228 : static void
229 7 : gnc_taxtable_finalize(GObject* ttp)
230 : {
231 7 : G_OBJECT_CLASS(gnc_taxtable_parent_class)->finalize(ttp);
232 7 : }
233 :
234 : static void
235 6 : gnc_taxtable_get_property (GObject *object,
236 : guint prop_id,
237 : GValue *value,
238 : GParamSpec *pspec)
239 : {
240 : GncTaxTable *tt;
241 :
242 6 : g_return_if_fail(GNC_IS_TAXTABLE(object));
243 :
244 6 : tt = GNC_TAXTABLE(object);
245 6 : switch (prop_id)
246 : {
247 2 : case PROP_NAME:
248 2 : g_value_set_string(value, tt->name);
249 2 : break;
250 2 : case PROP_INVISIBLE:
251 2 : g_value_set_boolean(value, tt->invisible);
252 2 : break;
253 2 : case PROP_REFCOUNT:
254 2 : g_value_set_uint64(value, tt->refcount);
255 2 : break;
256 0 : default:
257 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
258 0 : break;
259 : }
260 : }
261 :
262 : static void
263 6 : gnc_taxtable_set_property (GObject *object,
264 : guint prop_id,
265 : const GValue *value,
266 : GParamSpec *pspec)
267 : {
268 : GncTaxTable *tt;
269 :
270 6 : g_return_if_fail(GNC_IS_TAXTABLE(object));
271 :
272 6 : tt = GNC_TAXTABLE(object);
273 6 : g_assert (qof_instance_get_editlevel(tt));
274 :
275 6 : switch (prop_id)
276 : {
277 2 : case PROP_NAME:
278 2 : gncTaxTableSetName(tt, g_value_get_string(value));
279 2 : break;
280 2 : case PROP_INVISIBLE:
281 2 : if (g_value_get_boolean(value))
282 : {
283 0 : gncTaxTableMakeInvisible(tt);
284 : }
285 2 : break;
286 2 : case PROP_REFCOUNT:
287 2 : gncTaxTableSetRefcount(tt, g_value_get_uint64(value));
288 2 : break;
289 0 : default:
290 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
291 0 : break;
292 : }
293 : }
294 :
295 : /** Return displayable name */
296 : static gchar*
297 0 : impl_get_display_name(const QofInstance* inst)
298 : {
299 : GncTaxTable* tt;
300 :
301 0 : g_return_val_if_fail(inst != NULL, FALSE);
302 0 : g_return_val_if_fail(GNC_IS_TAXTABLE(inst), FALSE);
303 :
304 0 : tt = GNC_TAXTABLE(inst);
305 0 : return g_strdup_printf("Tax table %s", tt->name);
306 : }
307 :
308 : /** Does this object refer to a specific object */
309 : static gboolean
310 0 : impl_refers_to_object(const QofInstance* inst, const QofInstance* ref)
311 : {
312 : GncTaxTable* tt;
313 :
314 0 : g_return_val_if_fail(inst != NULL, FALSE);
315 0 : g_return_val_if_fail(GNC_IS_TAXTABLE(inst), FALSE);
316 :
317 0 : tt = GNC_TAXTABLE(inst);
318 :
319 0 : if (GNC_IS_ACCOUNT(ref))
320 : {
321 : GList* node;
322 :
323 0 : for (node = tt->entries; node != NULL; node = node->next)
324 : {
325 0 : GncTaxTableEntry* tte = node->data;
326 :
327 0 : if (tte->account == GNC_ACCOUNT(ref))
328 : {
329 0 : return TRUE;
330 : }
331 : }
332 : }
333 :
334 0 : 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*
344 0 : impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
345 : {
346 0 : if (!GNC_IS_ACCOUNT(ref))
347 : {
348 0 : return NULL;
349 : }
350 :
351 0 : return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
352 : }
353 :
354 : static void
355 7 : gnc_taxtable_class_init (GncTaxTableClass *klass)
356 : {
357 7 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
358 7 : QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
359 :
360 7 : gobject_class->dispose = gnc_taxtable_dispose;
361 7 : gobject_class->finalize = gnc_taxtable_finalize;
362 7 : gobject_class->set_property = gnc_taxtable_set_property;
363 7 : gobject_class->get_property = gnc_taxtable_get_property;
364 :
365 7 : qof_class->get_display_name = impl_get_display_name;
366 7 : qof_class->refers_to_object = impl_refers_to_object;
367 7 : qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
368 :
369 7 : 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 7 : 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 7 : 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 7 : }
403 :
404 : /* Create/Destroy Functions */
405 : GncTaxTable *
406 29 : gncTaxTableCreate (QofBook *book)
407 : {
408 : GncTaxTable *table;
409 29 : if (!book) return NULL;
410 :
411 29 : table = g_object_new (GNC_TYPE_TAXTABLE, NULL);
412 29 : qof_instance_init_data (&table->inst, _GNC_MOD_NAME, book);
413 29 : table->name = CACHE_INSERT ("");
414 29 : addObj (table);
415 29 : qof_event_gen (&table->inst, QOF_EVENT_CREATE, NULL);
416 29 : return table;
417 : }
418 :
419 : void
420 7 : gncTaxTableDestroy (GncTaxTable *table)
421 : {
422 7 : if (!table) return;
423 7 : qof_instance_set_destroying(table, TRUE);
424 7 : qof_instance_set_dirty (&table->inst);
425 7 : gncTaxTableCommitEdit (table);
426 : }
427 :
428 : static void
429 7 : gncTaxTableFree (GncTaxTable *table)
430 : {
431 : GList *list;
432 : GncTaxTable *child;
433 :
434 7 : if (!table) return;
435 :
436 7 : qof_event_gen (&table->inst, QOF_EVENT_DESTROY, NULL);
437 7 : CACHE_REMOVE (table->name);
438 7 : remObj (table);
439 :
440 : /* destroy the list of entries */
441 16 : for (list = table->entries; list; list = list->next)
442 9 : gncTaxTableEntryDestroy (list->data);
443 7 : g_list_free (table->entries);
444 :
445 7 : if (!qof_instance_get_destroying(table))
446 0 : PERR("free a taxtable without do_free set!");
447 :
448 : /* disconnect from parent */
449 7 : if (table->parent)
450 0 : gncTaxTableRemoveChild(table->parent, table);
451 :
452 : /* disconnect from the children */
453 7 : for (list = table->children; list; list = list->next)
454 : {
455 0 : child = list->data;
456 0 : gncTaxTableSetParent(child, NULL);
457 : }
458 7 : g_list_free(table->children);
459 :
460 : /* qof_instance_release (&table->inst); */
461 7 : g_object_unref (table);
462 : }
463 :
464 : /* =============================================================== */
465 :
466 31 : GncTaxTableEntry * gncTaxTableEntryCreate (void)
467 : {
468 : GncTaxTableEntry *entry;
469 31 : entry = g_new0 (GncTaxTableEntry, 1);
470 31 : entry->amount = gnc_numeric_zero ();
471 31 : return entry;
472 : }
473 :
474 9 : void gncTaxTableEntryDestroy (GncTaxTableEntry *entry)
475 : {
476 9 : if (!entry) return;
477 9 : g_free (entry);
478 : }
479 :
480 : /* =============================================================== */
481 : /* Set Functions */
482 :
483 29 : void gncTaxTableSetName (GncTaxTable *table, const char *name)
484 : {
485 29 : if (!table || !name) return;
486 29 : SET_STR (table, table->name, name);
487 29 : mark_table (table);
488 29 : maybe_resort_list (table);
489 29 : gncTaxTableCommitEdit (table);
490 : }
491 :
492 5 : void gncTaxTableSetParent (GncTaxTable *table, GncTaxTable *parent)
493 : {
494 5 : if (!table) return;
495 5 : gncTaxTableBeginEdit (table);
496 5 : if (table->parent)
497 0 : gncTaxTableRemoveChild(table->parent, table);
498 5 : table->parent = parent;
499 5 : if (parent)
500 5 : gncTaxTableAddChild(parent, table);
501 5 : table->refcount = 0;
502 5 : gncTaxTableMakeInvisible (table);
503 5 : mark_table (table);
504 5 : gncTaxTableCommitEdit (table);
505 : }
506 :
507 5 : void gncTaxTableSetChild (GncTaxTable *table, GncTaxTable *child)
508 : {
509 5 : if (!table) return;
510 5 : gncTaxTableBeginEdit (table);
511 5 : table->child = child;
512 5 : mark_table (table);
513 5 : gncTaxTableCommitEdit (table);
514 : }
515 :
516 106 : void gncTaxTableIncRef (GncTaxTable *table)
517 : {
518 106 : if (!table) return;
519 106 : if (table->parent || table->invisible) return; /* children dont need refcounts */
520 66 : gncTaxTableBeginEdit (table);
521 66 : table->refcount++;
522 66 : mark_table (table);
523 66 : gncTaxTableCommitEdit (table);
524 : }
525 :
526 46 : void gncTaxTableDecRef (GncTaxTable *table)
527 : {
528 46 : if (!table) return;
529 46 : if (table->parent || table->invisible) return; /* children dont need refcounts */
530 46 : g_return_if_fail (table->refcount > 0);
531 46 : gncTaxTableBeginEdit (table);
532 46 : table->refcount--;
533 46 : mark_table (table);
534 46 : gncTaxTableCommitEdit (table);
535 : }
536 :
537 3 : void gncTaxTableSetRefcount (GncTaxTable *table, gint64 refcount)
538 : {
539 3 : if (!table) return;
540 3 : g_return_if_fail (refcount >= 0);
541 3 : gncTaxTableBeginEdit (table);
542 3 : table->refcount = refcount;
543 3 : mark_table (table);
544 3 : gncTaxTableCommitEdit (table);
545 : }
546 :
547 5 : void gncTaxTableMakeInvisible (GncTaxTable *table)
548 : {
549 : struct _book_info *bi;
550 5 : if (!table) return;
551 5 : gncTaxTableBeginEdit (table);
552 5 : table->invisible = TRUE;
553 5 : bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
554 5 : bi->tables = g_list_remove (bi->tables, table);
555 5 : gncTaxTableCommitEdit (table);
556 : }
557 :
558 31 : void gncTaxTableEntrySetAccount (GncTaxTableEntry *entry, Account *account)
559 : {
560 31 : if (!entry || !account) return;
561 31 : if (entry->account == account) return;
562 31 : entry->account = account;
563 31 : if (entry->table)
564 : {
565 0 : mark_table (entry->table);
566 0 : mod_table (entry->table);
567 : }
568 : }
569 :
570 31 : void gncTaxTableEntrySetType (GncTaxTableEntry *entry, GncAmountType type)
571 : {
572 31 : if (!entry) return;
573 31 : if (entry->type == type) return;
574 31 : entry->type = type;
575 31 : if (entry->table)
576 : {
577 0 : mark_table (entry->table);
578 0 : mod_table (entry->table);
579 : }
580 : }
581 :
582 38 : void gncTaxTableEntrySetAmount (GncTaxTableEntry *entry, gnc_numeric amount)
583 : {
584 38 : if (!entry) return;
585 38 : if (gnc_numeric_eq (entry->amount, amount)) return;
586 34 : entry->amount = amount;
587 34 : if (entry->table)
588 : {
589 7 : mark_table (entry->table);
590 7 : mod_table (entry->table);
591 : }
592 : }
593 :
594 31 : void gncTaxTableAddEntry (GncTaxTable *table, GncTaxTableEntry *entry)
595 : {
596 31 : if (!table || !entry) return;
597 31 : if (entry->table == table) return; /* already mine */
598 :
599 31 : gncTaxTableBeginEdit (table);
600 31 : if (entry->table)
601 0 : gncTaxTableRemoveEntry (entry->table, entry);
602 :
603 31 : entry->table = table;
604 31 : table->entries = g_list_insert_sorted (table->entries, entry,
605 : (GCompareFunc)gncTaxTableEntryCompare);
606 31 : mark_table (table);
607 31 : mod_table (table);
608 31 : gncTaxTableCommitEdit (table);
609 : }
610 :
611 0 : void gncTaxTableRemoveEntry (GncTaxTable *table, GncTaxTableEntry *entry)
612 : {
613 0 : if (!table || !entry) return;
614 0 : gncTaxTableBeginEdit (table);
615 0 : entry->table = NULL;
616 0 : table->entries = g_list_remove (table->entries, entry);
617 0 : mark_table (table);
618 0 : mod_table (table);
619 0 : gncTaxTableCommitEdit (table);
620 : }
621 :
622 0 : void gncTaxTableChanged (GncTaxTable *table)
623 : {
624 0 : if (!table) return;
625 0 : gncTaxTableBeginEdit (table);
626 0 : table->child = NULL;
627 0 : gncTaxTableCommitEdit (table);
628 : }
629 :
630 : /* =============================================================== */
631 :
632 198 : void gncTaxTableBeginEdit (GncTaxTable *table)
633 : {
634 198 : qof_begin_edit(&table->inst);
635 198 : }
636 :
637 0 : static void gncTaxTableOnError (QofInstance *inst, QofBackendError errcode)
638 : {
639 0 : PERR("TaxTable QofBackend Failure: %d", errcode);
640 0 : gnc_engine_signal_commit_error( errcode );
641 0 : }
642 :
643 179 : static void gncTaxTableOnDone (QofInstance *inst) {}
644 :
645 7 : static void table_free (QofInstance *inst)
646 : {
647 7 : GncTaxTable *table = (GncTaxTable *) inst;
648 7 : gncTaxTableFree (table);
649 7 : }
650 :
651 198 : void gncTaxTableCommitEdit (GncTaxTable *table)
652 : {
653 : /* GnuCash 2.6.3 and earlier didn't handle taxtable kvp's... */
654 198 : if (qof_instance_has_kvp (QOF_INSTANCE (table)))
655 0 : gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (table)),
656 : GNC_FEATURE_KVP_EXTRA_DATA);
657 :
658 198 : if (!qof_commit_edit (QOF_INSTANCE(table))) return;
659 186 : qof_commit_edit_part2 (&table->inst, gncTaxTableOnError,
660 : gncTaxTableOnDone, table_free);
661 : }
662 :
663 :
664 : /* =============================================================== */
665 : /* Get Functions */
666 :
667 0 : GncTaxTable *gncTaxTableLookupByName (QofBook *book, const char *name)
668 : {
669 0 : GList *list = gncTaxTableGetTables (book);
670 :
671 0 : for ( ; list; list = list->next)
672 : {
673 0 : GncTaxTable *table = list->data;
674 0 : if (!g_strcmp0 (table->name, name))
675 0 : return list->data;
676 : }
677 0 : return NULL;
678 : }
679 :
680 : GncTaxTable*
681 0 : gncTaxTableGetDefault (QofBook *book, GncOwnerType type)
682 : {
683 0 : GSList *path = NULL;
684 0 : const GncGUID *guid = NULL;
685 0 : const char *vendor = "Default Vendor TaxTable";
686 0 : const char *customer = "Default Customer TaxTable";
687 0 : const char *section = "Business";
688 :
689 0 : g_return_val_if_fail (book != NULL, NULL);
690 0 : g_return_val_if_fail (type == GNC_OWNER_CUSTOMER || \
691 : type == GNC_OWNER_VENDOR, NULL);
692 0 : path = g_slist_prepend (path, type == GNC_OWNER_CUSTOMER ? (void*)customer : (void*)vendor);
693 0 : path = g_slist_prepend (path, (void*)section);
694 :
695 0 : guid = qof_book_get_guid_option (book, path);
696 0 : g_slist_free (path);
697 :
698 0 : return gncTaxTableLookup (book, guid);
699 : }
700 :
701 0 : GncTaxTableList * gncTaxTableGetTables (QofBook *book)
702 : {
703 : struct _book_info *bi;
704 0 : if (!book) return NULL;
705 :
706 0 : bi = qof_book_get_data (book, _GNC_MOD_NAME);
707 0 : return bi ? bi->tables : NULL;
708 : }
709 :
710 0 : const char *gncTaxTableGetName (const GncTaxTable *table)
711 : {
712 0 : if (!table) return NULL;
713 0 : return table->name;
714 : }
715 :
716 5 : static GncTaxTableEntry *gncTaxTableEntryCopy (const GncTaxTableEntry *entry)
717 : {
718 : GncTaxTableEntry *e;
719 5 : if (!entry) return NULL;
720 :
721 5 : e = gncTaxTableEntryCreate ();
722 5 : gncTaxTableEntrySetAccount (e, entry->account);
723 5 : gncTaxTableEntrySetType (e, entry->type);
724 5 : gncTaxTableEntrySetAmount (e, entry->amount);
725 :
726 5 : return e;
727 : }
728 :
729 5 : static GncTaxTable *gncTaxTableCopy (const GncTaxTable *table)
730 : {
731 : GncTaxTable *t;
732 : GList *list;
733 :
734 5 : if (!table) return NULL;
735 5 : t = gncTaxTableCreate (qof_instance_get_book(table));
736 5 : gncTaxTableSetName (t, table->name);
737 10 : for (list = table->entries; list; list = list->next)
738 : {
739 : GncTaxTableEntry *entry, *e;
740 5 : entry = list->data;
741 5 : e = gncTaxTableEntryCopy (entry);
742 : /* Clang static analyzer thinks we're leaking e, but we're not.
743 : * We're transferring it to table. */
744 5 : gncTaxTableAddEntry (t, e);
745 : }
746 5 : return t;
747 : }
748 :
749 108 : GncTaxTable *gncTaxTableReturnChild (GncTaxTable *table, gboolean make_new)
750 : {
751 108 : GncTaxTable *child = NULL;
752 :
753 108 : if (!table) return NULL;
754 40 : if (table->child) return table->child;
755 5 : if (table->parent || table->invisible) return table;
756 5 : if (make_new)
757 : {
758 5 : child = gncTaxTableCopy (table);
759 5 : gncTaxTableSetChild (table, child);
760 5 : gncTaxTableSetParent (child, table);
761 : }
762 5 : return child;
763 : }
764 :
765 13 : GncTaxTable *gncTaxTableGetParent (const GncTaxTable *table)
766 : {
767 13 : if (!table) return NULL;
768 5 : return table->parent;
769 : }
770 :
771 319 : GncTaxTableEntryList* gncTaxTableGetEntries (const GncTaxTable *table)
772 : {
773 319 : if (!table) return NULL;
774 63 : return table->entries;
775 : }
776 :
777 0 : gint64 gncTaxTableGetRefcount (const GncTaxTable *table)
778 : {
779 0 : if (!table) return 0;
780 0 : return table->refcount;
781 : }
782 :
783 528 : time64 gncTaxTableLastModifiedSecs (const GncTaxTable *table)
784 : {
785 528 : if (!table) return 0;
786 528 : return table->modtime;
787 : }
788 :
789 0 : gboolean gncTaxTableGetInvisible (const GncTaxTable *table)
790 : {
791 0 : if (!table) return FALSE;
792 0 : return table->invisible;
793 : }
794 :
795 63 : Account * gncTaxTableEntryGetAccount (const GncTaxTableEntry *entry)
796 : {
797 63 : if (!entry) return NULL;
798 63 : return entry->account;
799 : }
800 :
801 123 : GncAmountType gncTaxTableEntryGetType (const GncTaxTableEntry *entry)
802 : {
803 123 : if (!entry) return 0;
804 123 : return entry->type;
805 : }
806 :
807 123 : gnc_numeric gncTaxTableEntryGetAmount (const GncTaxTableEntry *entry)
808 : {
809 123 : if (!entry) return gnc_numeric_zero();
810 123 : 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 3 : GncTaxTable* gncTaxTableEntryGetTable( const GncTaxTableEntry* entry )
816 : {
817 3 : if (!entry) return NULL;
818 3 : return entry->table;
819 : }
820 :
821 2 : int gncTaxTableEntryCompare (const GncTaxTableEntry *a, const GncTaxTableEntry *b)
822 : {
823 : char *name_a, *name_b;
824 : int retval;
825 :
826 2 : if (!a && !b) return 0;
827 2 : if (!a) return -1;
828 2 : if (!b) return 1;
829 :
830 2 : name_a = gnc_account_get_full_name (a->account);
831 2 : name_b = gnc_account_get_full_name (b->account);
832 2 : retval = g_strcmp0(name_a, name_b);
833 2 : g_free(name_a);
834 2 : g_free(name_b);
835 :
836 2 : if (retval)
837 2 : return retval;
838 :
839 0 : return gnc_numeric_compare (a->amount, b->amount);
840 : }
841 :
842 137 : int gncTaxTableCompare (const GncTaxTable *a, const GncTaxTable *b)
843 : {
844 137 : if (!a && !b) return 0;
845 137 : if (!a) return -1;
846 137 : if (!b) return 1;
847 137 : return g_strcmp0 (a->name, b->name);
848 : }
849 :
850 2 : gboolean gncTaxTableEntryEqual(const GncTaxTableEntry *a, const GncTaxTableEntry *b)
851 : {
852 2 : if (a == NULL && b == NULL) return TRUE;
853 2 : if (a == NULL || b == NULL) return FALSE;
854 :
855 2 : if (!xaccAccountEqual(a->account, b->account, TRUE))
856 : {
857 0 : PWARN("accounts differ");
858 0 : return FALSE;
859 : }
860 :
861 2 : if (a->type != b->type)
862 : {
863 0 : PWARN("types differ");
864 0 : return FALSE;
865 : }
866 :
867 2 : if (!gnc_numeric_equal(a->amount, b->amount))
868 : {
869 0 : PWARN("amounts differ");
870 0 : return FALSE;
871 : }
872 :
873 2 : return TRUE;
874 : }
875 :
876 6 : gboolean gncTaxTableEqual(const GncTaxTable *a, const GncTaxTable *b)
877 : {
878 6 : if (a == NULL && b == NULL) return TRUE;
879 1 : if (a == NULL || b == NULL) return FALSE;
880 :
881 1 : g_return_val_if_fail(GNC_IS_TAXTABLE(a), FALSE);
882 1 : g_return_val_if_fail(GNC_IS_TAXTABLE(b), FALSE);
883 :
884 1 : if (g_strcmp0(a->name, b->name) != 0)
885 : {
886 0 : PWARN("Names differ: %s vs %s", a->name, b->name);
887 0 : return FALSE;
888 : }
889 :
890 1 : if (a->invisible != b->invisible)
891 : {
892 0 : PWARN("invisible flags differ");
893 0 : return FALSE;
894 : }
895 :
896 1 : if ((a->entries != NULL) != (b->entries != NULL))
897 : {
898 0 : PWARN("only one has entries");
899 0 : return FALSE;
900 : }
901 :
902 1 : if (a->entries != NULL && b->entries != NULL)
903 : {
904 : GncTaxTableEntryList* a_node;
905 : GncTaxTableEntryList* b_node;
906 :
907 1 : for (a_node = a->entries, b_node = b->entries;
908 3 : a_node != NULL && b_node != NULL;
909 2 : a_node = a_node->next, b_node = b_node->next)
910 : {
911 2 : if (!gncTaxTableEntryEqual((GncTaxTableEntry*)a_node->data,
912 2 : (GncTaxTableEntry*)b_node->data))
913 : {
914 0 : PWARN("entries differ");
915 0 : return FALSE;
916 : }
917 : }
918 :
919 1 : if (a_node != NULL || b_node != NULL)
920 : {
921 0 : PWARN("Unequal number of entries");
922 0 : 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 1 : 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 422 : GList *gncAccountValueAdd (GList *list, Account *acc, gnc_numeric value)
943 : {
944 : GList *li;
945 422 : GncAccountValue *res = NULL;
946 :
947 422 : g_return_val_if_fail (acc, list);
948 422 : g_return_val_if_fail (gnc_numeric_check (value) == GNC_ERROR_OK, list);
949 :
950 : /* Try to find the account in the list */
951 427 : for (li = list; li; li = li->next)
952 : {
953 140 : res = li->data;
954 140 : if (res->account == acc)
955 : {
956 135 : res->value = gnc_numeric_add (res->value, value, GNC_DENOM_AUTO,
957 : GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND_HALF_UP);
958 135 : return list;
959 : }
960 : }
961 : /* Nope, didn't find it. */
962 :
963 287 : res = g_new0 (GncAccountValue, 1);
964 287 : res->account = acc;
965 287 : res->value = value;
966 287 : return g_list_prepend (list, res);
967 : }
968 :
969 : /* Merge l2 into l1. l2 is not touched. */
970 564 : GList *gncAccountValueAddList (GList *l1, GList *l2)
971 : {
972 : GList *li;
973 :
974 694 : for (li = l2; li; li = li->next )
975 : {
976 130 : GncAccountValue *val = li->data;
977 130 : l1 = gncAccountValueAdd (l1, val->account, val->value);
978 : }
979 :
980 564 : return l1;
981 : }
982 :
983 : /* return the total for this list */
984 316 : gnc_numeric gncAccountValueTotal (GList *list)
985 : {
986 316 : gnc_numeric total = gnc_numeric_zero ();
987 :
988 376 : for ( ; list ; list = list->next)
989 : {
990 60 : GncAccountValue *val = list->data;
991 60 : total = gnc_numeric_add (total, val->value, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND_HALF_UP);
992 : }
993 316 : return total;
994 : }
995 :
996 : /* Destroy a list of accountvalues */
997 891 : void gncAccountValueDestroy (GList *list)
998 : {
999 : GList *node;
1000 1149 : for ( node = list; node ; node = node->next)
1001 258 : g_free (node->data);
1002 :
1003 891 : g_list_free (list);
1004 891 : }
1005 :
1006 : /* Package-Private functions */
1007 :
1008 431 : static void _gncTaxTableCreate (QofBook *book)
1009 : {
1010 : struct _book_info *bi;
1011 :
1012 431 : if (!book) return;
1013 :
1014 431 : bi = g_new0 (struct _book_info, 1);
1015 431 : qof_book_set_data (book, _GNC_MOD_NAME, bi);
1016 : }
1017 :
1018 : static void
1019 6 : destroy_taxtable_on_book_close (QofInstance *ent, gpointer data)
1020 : {
1021 6 : GncTaxTable *table = GNC_TAXTABLE(ent);
1022 :
1023 6 : gncTaxTableBeginEdit (table);
1024 6 : gncTaxTableDestroy (table);
1025 6 : }
1026 :
1027 301 : static void _gncTaxTableDestroy (QofBook *book)
1028 : {
1029 : struct _book_info *bi;
1030 : QofCollection *col;
1031 :
1032 301 : if (!book) return;
1033 :
1034 301 : bi = qof_book_get_data (book, _GNC_MOD_NAME);
1035 :
1036 301 : col = qof_book_get_collection (book, GNC_ID_TAXTABLE);
1037 301 : qof_collection_foreach (col, destroy_taxtable_on_book_close, NULL);
1038 :
1039 301 : g_list_free (bi->tables);
1040 301 : 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 84 : 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 84 : qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncTaxTableCompare, params);
1070 :
1071 84 : 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);
|