Branch data 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 : 33 : gncAmountTypeToString (GncAmountType type)
80 : : {
81 : 33 : switch (type)
82 : : {
83 : 16 : GNC_RETURN_ENUM_AS_STRING(GNC_AMT_TYPE_VALUE, "VALUE");
84 : 17 : 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 : 2 : gncAmountStringToType (const char *str, GncAmountType *type)
111 : : {
112 : 2 : GNC_RETURN_ON_MATCH ("VALUE", GNC_AMT_TYPE_VALUE);
113 : 2 : 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 : 4 : gncTaxIncludedStringToType (const char *str, GncTaxIncluded *type)
122 : : {
123 : 4 : GNC_RETURN_ON_MATCH ("YES", GNC_TAXINCLUDED_YES);
124 : 4 : GNC_RETURN_ON_MATCH ("NO", GNC_TAXINCLUDED_NO);
125 : 4 : 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 : 163 : mark_table (GncTaxTable *table)
146 : : {
147 : 163 : qof_instance_set_dirty(&table->inst);
148 : 163 : qof_event_gen (&table->inst, QOF_EVENT_MODIFY, NULL);
149 : 163 : }
150 : :
151 : : static inline void
152 : 25 : maybe_resort_list (GncTaxTable *table)
153 : : {
154 : : struct _book_info *bi;
155 : :
156 : 25 : if (table->parent || table->invisible) return;
157 : 25 : bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
158 : 25 : bi->tables = g_list_sort (bi->tables, (GCompareFunc)gncTaxTableCompare);
159 : : }
160 : :
161 : : static inline void
162 : 34 : mod_table (GncTaxTable *table)
163 : : {
164 : 34 : table->modtime = gnc_time (NULL);
165 : 34 : }
166 : :
167 : 25 : static inline void addObj (GncTaxTable *table)
168 : : {
169 : : struct _book_info *bi;
170 : 25 : bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
171 : 25 : bi->tables = g_list_insert_sorted (bi->tables, table,
172 : : (GCompareFunc)gncTaxTableCompare);
173 : 25 : }
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 : 4 : gncTaxTableAddChild (GncTaxTable *table, GncTaxTable *child)
184 : : {
185 : 4 : g_return_if_fail(table);
186 : 4 : g_return_if_fail(child);
187 : 4 : g_return_if_fail(qof_instance_get_destroying(table) == FALSE);
188 : :
189 : 4 : 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 : 89 : G_DEFINE_TYPE(GncTaxTable, gnc_taxtable, QOF_TYPE_INSTANCE)
216 : :
217 : : static void
218 : 25 : gnc_taxtable_init(GncTaxTable* tt)
219 : : {
220 : 25 : }
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)->dispose(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 : 6 : gnc_taxtable_class_init (GncTaxTableClass *klass)
356 : : {
357 : 6 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
358 : 6 : QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
359 : :
360 : 6 : gobject_class->dispose = gnc_taxtable_dispose;
361 : 6 : gobject_class->finalize = gnc_taxtable_finalize;
362 : 6 : gobject_class->set_property = gnc_taxtable_set_property;
363 : 6 : gobject_class->get_property = gnc_taxtable_get_property;
364 : :
365 : 6 : qof_class->get_display_name = impl_get_display_name;
366 : 6 : qof_class->refers_to_object = impl_refers_to_object;
367 : 6 : qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
368 : :
369 : 6 : 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 : 6 : 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 : 6 : 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 : 6 : }
403 : :
404 : : /* Create/Destroy Functions */
405 : : GncTaxTable *
406 : 25 : gncTaxTableCreate (QofBook *book)
407 : : {
408 : : GncTaxTable *table;
409 : 25 : if (!book) return NULL;
410 : :
411 : 25 : table = g_object_new (GNC_TYPE_TAXTABLE, NULL);
412 : 25 : qof_instance_init_data (&table->inst, _GNC_MOD_NAME, book);
413 : 25 : table->name = CACHE_INSERT ("");
414 : 25 : addObj (table);
415 : 25 : qof_event_gen (&table->inst, QOF_EVENT_CREATE, NULL);
416 : 25 : 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 : 27 : GncTaxTableEntry * gncTaxTableEntryCreate (void)
467 : : {
468 : : GncTaxTableEntry *entry;
469 : 27 : entry = g_new0 (GncTaxTableEntry, 1);
470 : 27 : entry->amount = gnc_numeric_zero ();
471 : 27 : 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 : 25 : void gncTaxTableSetName (GncTaxTable *table, const char *name)
484 : : {
485 : 25 : if (!table || !name) return;
486 : 25 : SET_STR (table, table->name, name);
487 : 25 : mark_table (table);
488 : 25 : maybe_resort_list (table);
489 : 25 : gncTaxTableCommitEdit (table);
490 : : }
491 : :
492 : 4 : void gncTaxTableSetParent (GncTaxTable *table, GncTaxTable *parent)
493 : : {
494 : 4 : if (!table) return;
495 : 4 : gncTaxTableBeginEdit (table);
496 : 4 : if (table->parent)
497 : 0 : gncTaxTableRemoveChild(table->parent, table);
498 : 4 : table->parent = parent;
499 : 4 : if (parent)
500 : 4 : gncTaxTableAddChild(parent, table);
501 : 4 : table->refcount = 0;
502 : 4 : gncTaxTableMakeInvisible (table);
503 : 4 : mark_table (table);
504 : 4 : gncTaxTableCommitEdit (table);
505 : : }
506 : :
507 : 4 : void gncTaxTableSetChild (GncTaxTable *table, GncTaxTable *child)
508 : : {
509 : 4 : if (!table) return;
510 : 4 : gncTaxTableBeginEdit (table);
511 : 4 : table->child = child;
512 : 4 : mark_table (table);
513 : 4 : gncTaxTableCommitEdit (table);
514 : : }
515 : :
516 : 87 : void gncTaxTableIncRef (GncTaxTable *table)
517 : : {
518 : 87 : if (!table) return;
519 : 87 : if (table->parent || table->invisible) return; /* children dont need refcounts */
520 : 55 : gncTaxTableBeginEdit (table);
521 : 55 : table->refcount++;
522 : 55 : mark_table (table);
523 : 55 : gncTaxTableCommitEdit (table);
524 : : }
525 : :
526 : 38 : void gncTaxTableDecRef (GncTaxTable *table)
527 : : {
528 : 38 : if (!table) return;
529 : 38 : if (table->parent || table->invisible) return; /* children dont need refcounts */
530 : 38 : g_return_if_fail (table->refcount > 0);
531 : 38 : gncTaxTableBeginEdit (table);
532 : 38 : table->refcount--;
533 : 38 : mark_table (table);
534 : 38 : 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 : 4 : void gncTaxTableMakeInvisible (GncTaxTable *table)
548 : : {
549 : : struct _book_info *bi;
550 : 4 : if (!table) return;
551 : 4 : gncTaxTableBeginEdit (table);
552 : 4 : table->invisible = TRUE;
553 : 4 : bi = qof_book_get_data (qof_instance_get_book(table), _GNC_MOD_NAME);
554 : 4 : bi->tables = g_list_remove (bi->tables, table);
555 : 4 : gncTaxTableCommitEdit (table);
556 : : }
557 : :
558 : 27 : void gncTaxTableEntrySetAccount (GncTaxTableEntry *entry, Account *account)
559 : : {
560 : 27 : if (!entry || !account) return;
561 : 27 : if (entry->account == account) return;
562 : 27 : entry->account = account;
563 : 27 : if (entry->table)
564 : : {
565 : 0 : mark_table (entry->table);
566 : 0 : mod_table (entry->table);
567 : : }
568 : : }
569 : :
570 : 27 : void gncTaxTableEntrySetType (GncTaxTableEntry *entry, GncAmountType type)
571 : : {
572 : 27 : if (!entry) return;
573 : 27 : if (entry->type == type) return;
574 : 27 : entry->type = type;
575 : 27 : if (entry->table)
576 : : {
577 : 0 : mark_table (entry->table);
578 : 0 : mod_table (entry->table);
579 : : }
580 : : }
581 : :
582 : 34 : void gncTaxTableEntrySetAmount (GncTaxTableEntry *entry, gnc_numeric amount)
583 : : {
584 : 34 : if (!entry) return;
585 : 34 : if (gnc_numeric_eq (entry->amount, amount)) return;
586 : 30 : entry->amount = amount;
587 : 30 : if (entry->table)
588 : : {
589 : 7 : mark_table (entry->table);
590 : 7 : mod_table (entry->table);
591 : : }
592 : : }
593 : :
594 : 27 : void gncTaxTableAddEntry (GncTaxTable *table, GncTaxTableEntry *entry)
595 : : {
596 : 27 : if (!table || !entry) return;
597 : 27 : if (entry->table == table) return; /* already mine */
598 : :
599 : 27 : gncTaxTableBeginEdit (table);
600 : 27 : if (entry->table)
601 : 0 : gncTaxTableRemoveEntry (entry->table, entry);
602 : :
603 : 27 : entry->table = table;
604 : 27 : table->entries = g_list_insert_sorted (table->entries, entry,
605 : : (GCompareFunc)gncTaxTableEntryCompare);
606 : 27 : mark_table (table);
607 : 27 : mod_table (table);
608 : 27 : 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 : 168 : void gncTaxTableBeginEdit (GncTaxTable *table)
633 : : {
634 : 168 : qof_begin_edit(&table->inst);
635 : 168 : }
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 : 150 : 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 : 168 : void gncTaxTableCommitEdit (GncTaxTable *table)
652 : : {
653 : : /* GnuCash 2.6.3 and earlier didn't handle taxtable kvp's... */
654 : 168 : 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 : 168 : if (!qof_commit_edit (QOF_INSTANCE(table))) return;
659 : 157 : 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 : 4 : static GncTaxTableEntry *gncTaxTableEntryCopy (const GncTaxTableEntry *entry)
717 : : {
718 : : GncTaxTableEntry *e;
719 : 4 : if (!entry) return NULL;
720 : :
721 : 4 : e = gncTaxTableEntryCreate ();
722 : 4 : gncTaxTableEntrySetAccount (e, entry->account);
723 : 4 : gncTaxTableEntrySetType (e, entry->type);
724 : 4 : gncTaxTableEntrySetAmount (e, entry->amount);
725 : :
726 : 4 : return e;
727 : : }
728 : :
729 : 4 : static GncTaxTable *gncTaxTableCopy (const GncTaxTable *table)
730 : : {
731 : : GncTaxTable *t;
732 : : GList *list;
733 : :
734 : 4 : if (!table) return NULL;
735 : 4 : t = gncTaxTableCreate (qof_instance_get_book(table));
736 : 4 : gncTaxTableSetName (t, table->name);
737 : 8 : for (list = table->entries; list; list = list->next)
738 : : {
739 : : GncTaxTableEntry *entry, *e;
740 : 4 : entry = list->data;
741 : 4 : e = gncTaxTableEntryCopy (entry);
742 : : /* Clang static analyzer thinks we're leaking e, but we're not.
743 : : * We're transferring it to table. */
744 : 4 : gncTaxTableAddEntry (t, e);
745 : : }
746 : 4 : return t;
747 : : }
748 : :
749 : 91 : GncTaxTable *gncTaxTableReturnChild (GncTaxTable *table, gboolean make_new)
750 : : {
751 : 91 : GncTaxTable *child = NULL;
752 : :
753 : 91 : if (!table) return NULL;
754 : 32 : if (table->child) return table->child;
755 : 4 : if (table->parent || table->invisible) return table;
756 : 4 : if (make_new)
757 : : {
758 : 4 : child = gncTaxTableCopy (table);
759 : 4 : gncTaxTableSetChild (table, child);
760 : 4 : gncTaxTableSetParent (child, table);
761 : : }
762 : 4 : 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 : 269 : GncTaxTableEntryList* gncTaxTableGetEntries (const GncTaxTable *table)
772 : : {
773 : 269 : if (!table) return NULL;
774 : 53 : 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 : 488 : time64 gncTaxTableLastModifiedSecs (const GncTaxTable *table)
784 : : {
785 : 488 : if (!table) return 0;
786 : 488 : 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 : 53 : Account * gncTaxTableEntryGetAccount (const GncTaxTableEntry *entry)
796 : : {
797 : 53 : if (!entry) return NULL;
798 : 53 : return entry->account;
799 : : }
800 : :
801 : 103 : GncAmountType gncTaxTableEntryGetType (const GncTaxTableEntry *entry)
802 : : {
803 : 103 : if (!entry) return 0;
804 : 103 : return entry->type;
805 : : }
806 : :
807 : 103 : gnc_numeric gncTaxTableEntryGetAmount (const GncTaxTableEntry *entry)
808 : : {
809 : 103 : if (!entry) return gnc_numeric_zero();
810 : 103 : 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 : 125 : int gncTaxTableCompare (const GncTaxTable *a, const GncTaxTable *b)
843 : : {
844 : 125 : if (!a && !b) return 0;
845 : 125 : if (!a) return -1;
846 : 125 : if (!b) return 1;
847 : 125 : 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 : 374 : GList *gncAccountValueAdd (GList *list, Account *acc, gnc_numeric value)
943 : : {
944 : : GList *li;
945 : 374 : GncAccountValue *res = NULL;
946 : :
947 : 374 : g_return_val_if_fail (acc, list);
948 : 374 : g_return_val_if_fail (gnc_numeric_check (value) == GNC_ERROR_OK, list);
949 : :
950 : : /* Try to find the account in the list */
951 : 378 : for (li = list; li; li = li->next)
952 : : {
953 : 124 : res = li->data;
954 : 124 : if (res->account == acc)
955 : : {
956 : 120 : res->value = gnc_numeric_add (res->value, value, GNC_DENOM_AUTO,
957 : : GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND_HALF_UP);
958 : 120 : return list;
959 : : }
960 : : }
961 : : /* Nope, didn't find it. */
962 : :
963 : 254 : res = g_new0 (GncAccountValue, 1);
964 : 254 : res->account = acc;
965 : 254 : res->value = value;
966 : 254 : return g_list_prepend (list, res);
967 : : }
968 : :
969 : : /* Merge l2 into l1. l2 is not touched. */
970 : 520 : GList *gncAccountValueAddList (GList *l1, GList *l2)
971 : : {
972 : : GList *li;
973 : :
974 : 639 : for (li = l2; li; li = li->next )
975 : : {
976 : 119 : GncAccountValue *val = li->data;
977 : 119 : l1 = gncAccountValueAdd (l1, val->account, val->value);
978 : : }
979 : :
980 : 520 : return l1;
981 : : }
982 : :
983 : : /* return the total for this list */
984 : 266 : gnc_numeric gncAccountValueTotal (GList *list)
985 : : {
986 : 266 : gnc_numeric total = gnc_numeric_zero ();
987 : :
988 : 316 : for ( ; list ; list = list->next)
989 : : {
990 : 50 : GncAccountValue *val = list->data;
991 : 50 : total = gnc_numeric_add (total, val->value, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND_HALF_UP);
992 : : }
993 : 266 : return total;
994 : : }
995 : :
996 : : /* Destroy a list of accountvalues */
997 : 822 : void gncAccountValueDestroy (GList *list)
998 : : {
999 : : GList *node;
1000 : 1052 : for ( node = list; node ; node = node->next)
1001 : 230 : g_free (node->data);
1002 : :
1003 : 822 : g_list_free (list);
1004 : 822 : }
1005 : :
1006 : : /* Package-Private functions */
1007 : :
1008 : 377 : static void _gncTaxTableCreate (QofBook *book)
1009 : : {
1010 : : struct _book_info *bi;
1011 : :
1012 : 377 : if (!book) return;
1013 : :
1014 : 377 : bi = g_new0 (struct _book_info, 1);
1015 : 377 : 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 : 270 : static void _gncTaxTableDestroy (QofBook *book)
1028 : : {
1029 : : struct _book_info *bi;
1030 : : QofCollection *col;
1031 : :
1032 : 270 : if (!book) return;
1033 : :
1034 : 270 : bi = qof_book_get_data (book, _GNC_MOD_NAME);
1035 : :
1036 : 270 : col = qof_book_get_collection (book, GNC_ID_TAXTABLE);
1037 : 270 : qof_collection_foreach (col, destroy_taxtable_on_book_close, NULL);
1038 : :
1039 : 270 : g_list_free (bi->tables);
1040 : 270 : 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 : 82 : 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 : 82 : qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncTaxTableCompare, params);
1070 : :
1071 : 82 : 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);
|