Branch data Line data Source code
1 : : /********************************************************************\
2 : : * gnc-bill-term-xml-v2.c -- billing term xml i/o implementation *
3 : : * *
4 : : * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU> *
5 : : * *
6 : : * This program is free software; you can redistribute it and/or *
7 : : * modify it under the terms of the GNU General Public License as *
8 : : * published by the Free Software Foundation; either version 2 of *
9 : : * the License, or (at your option) any later version. *
10 : : * *
11 : : * This program is distributed in the hope that it will be useful, *
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 : : * GNU General Public License for more details. *
15 : : * *
16 : : * You should have received a copy of the GNU General Public License*
17 : : * along with this program; if not, contact: *
18 : : * *
19 : : * Free Software Foundation Voice: +1-617-542-5942 *
20 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
22 : : * *
23 : : \********************************************************************/
24 : : #include <config.h>
25 : : #include <stdlib.h>
26 : : #include <string.h>
27 : :
28 : : #include "gncBillTermP.h"
29 : : #include "gncInvoice.h"
30 : : #include "qof.h"
31 : :
32 : : #include "gnc-xml-helper.h"
33 : :
34 : : #include "sixtp.h"
35 : : #include "sixtp-utils.h"
36 : : #include "sixtp-parsers.h"
37 : : #include "sixtp-utils.h"
38 : : #include "sixtp-dom-parsers.h"
39 : : #include "sixtp-dom-generators.h"
40 : :
41 : : #include "gnc-xml.h"
42 : : #include "io-gncxml-gen.h"
43 : : #include "io-gncxml-v2.h"
44 : : #include "gnc-bill-term-xml-v2.h"
45 : :
46 : : #include "xml-helpers.h"
47 : :
48 : : #define _GNC_MOD_NAME GNC_ID_BILLTERM
49 : :
50 : : static QofLogModule log_module = GNC_MOD_IO;
51 : :
52 : : const gchar* billterm_version_string = "2.0.0";
53 : :
54 : : /* ids */
55 : : #define gnc_billterm_string "gnc:GncBillTerm"
56 : : #define billterm_guid_string "billterm:guid"
57 : : #define billterm_name_string "billterm:name"
58 : : #define billterm_desc_string "billterm:desc"
59 : : #define billterm_refcount_string "billterm:refcount"
60 : : #define billterm_invisible_string "billterm:invisible"
61 : : #define billterm_parent_string "billterm:parent"
62 : : #define billterm_child_string "billterm:child"
63 : : #define billterm_slots_string "billterm:slots"
64 : :
65 : : #define gnc_daystype_string "billterm:days"
66 : : #define days_duedays_string "bt-days:due-days"
67 : : #define days_discdays_string "bt-days:disc-days"
68 : : #define days_discount_string "bt-days:discount"
69 : :
70 : : #define gnc_proximotype_string "billterm:proximo"
71 : : #define prox_dueday_string "bt-prox:due-day"
72 : : #define prox_discday_string "bt-prox:disc-day"
73 : : #define prox_discount_string "bt-prox:discount"
74 : : #define prox_cutoff_string "bt-prox:cutoff-day"
75 : :
76 : : static xmlNodePtr
77 : 0 : billterm_dom_tree_create (GncBillTerm* term)
78 : : {
79 : : xmlNodePtr ret, data;
80 : :
81 : 0 : ret = xmlNewNode (NULL, BAD_CAST gnc_billterm_string);
82 : 0 : xmlSetProp (ret, BAD_CAST "version", BAD_CAST billterm_version_string);
83 : :
84 : 0 : maybe_add_guid (ret, billterm_guid_string, QOF_INSTANCE (term));
85 : 0 : xmlAddChild (ret, text_to_dom_tree (billterm_name_string,
86 : : gncBillTermGetName (term)));
87 : 0 : xmlAddChild (ret, text_to_dom_tree (billterm_desc_string,
88 : : gncBillTermGetDescription (term)));
89 : :
90 : 0 : xmlAddChild (ret, int_to_dom_tree (billterm_refcount_string,
91 : : gncBillTermGetRefcount (term)));
92 : 0 : xmlAddChild (ret, int_to_dom_tree (billterm_invisible_string,
93 : 0 : gncBillTermGetInvisible (term)));
94 : :
95 : : /* xmlAddChild won't do anything with a NULL, so tests are superfluous. */
96 : 0 : xmlAddChild (ret, qof_instance_slots_to_dom_tree (billterm_slots_string,
97 : 0 : QOF_INSTANCE (term)));
98 : :
99 : : /* We should not be our own child */
100 : 0 : if (gncBillTermGetChild (term) != term)
101 : 0 : maybe_add_guid (ret, billterm_child_string,
102 : 0 : QOF_INSTANCE (gncBillTermGetChild (term)));
103 : :
104 : 0 : maybe_add_guid (ret, billterm_parent_string,
105 : 0 : QOF_INSTANCE (gncBillTermGetParent (term)));
106 : :
107 : 0 : switch (gncBillTermGetType (term))
108 : : {
109 : 0 : case GNC_TERM_TYPE_DAYS:
110 : 0 : data = xmlNewChild (ret, NULL, BAD_CAST gnc_daystype_string, NULL);
111 : 0 : maybe_add_int (data, days_duedays_string, gncBillTermGetDueDays (term));
112 : 0 : maybe_add_int (data, days_discdays_string,
113 : : gncBillTermGetDiscountDays (term));
114 : 0 : maybe_add_numeric (data, days_discount_string,
115 : : gncBillTermGetDiscount (term));
116 : 0 : break;
117 : :
118 : 0 : case GNC_TERM_TYPE_PROXIMO:
119 : 0 : data = xmlNewChild (ret, NULL, BAD_CAST gnc_proximotype_string, NULL);
120 : 0 : maybe_add_int (data, prox_dueday_string, gncBillTermGetDueDays (term));
121 : 0 : maybe_add_int (data, prox_discday_string,
122 : : gncBillTermGetDiscountDays (term));
123 : 0 : maybe_add_numeric (data, prox_discount_string,
124 : : gncBillTermGetDiscount (term));
125 : 0 : maybe_add_int (data, prox_cutoff_string, gncBillTermGetCutoff (term));
126 : 0 : break;
127 : : }
128 : :
129 : 0 : return ret;
130 : : }
131 : :
132 : : /***********************************************************************/
133 : :
134 : : struct billterm_pdata
135 : : {
136 : : GncBillTerm* term;
137 : : QofBook* book;
138 : : };
139 : :
140 : : static gboolean
141 : 0 : set_int (xmlNodePtr node, GncBillTerm* term,
142 : : void (*func) (GncBillTerm*, gint))
143 : : {
144 : : gint64 val;
145 : 0 : dom_tree_to_integer (node, &val);
146 : 0 : func (term, val);
147 : 0 : return TRUE;
148 : : }
149 : :
150 : : static gboolean
151 : 0 : set_numeric (xmlNodePtr node, GncBillTerm* term,
152 : : void (*func) (GncBillTerm*, gnc_numeric))
153 : : {
154 : 0 : func (term, dom_tree_to_gnc_numeric (node));
155 : 0 : return TRUE;
156 : : }
157 : :
158 : : /***********************************************************************/
159 : :
160 : : static gboolean
161 : 0 : days_duedays_handler (xmlNodePtr node, gpointer billterm_pdata)
162 : : {
163 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
164 : 0 : return set_int (node, pdata->term, gncBillTermSetDueDays);
165 : : }
166 : :
167 : : static gboolean
168 : 0 : days_discdays_handler (xmlNodePtr node, gpointer billterm_pdata)
169 : : {
170 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
171 : 0 : return set_int (node, pdata->term, gncBillTermSetDiscountDays);
172 : : }
173 : :
174 : : static gboolean
175 : 0 : days_discount_handler (xmlNodePtr node, gpointer billterm_pdata)
176 : : {
177 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
178 : 0 : return set_numeric (node, pdata->term, gncBillTermSetDiscount);
179 : : }
180 : :
181 : : static struct dom_tree_handler days_data_handlers_v2[] =
182 : : {
183 : : { days_duedays_string, days_duedays_handler, 0, 0 },
184 : : { days_discdays_string, days_discdays_handler, 0, 0 },
185 : : { days_discount_string, days_discount_handler, 0, 0 },
186 : : { NULL, 0, 0, 0 }
187 : : };
188 : :
189 : : static gboolean
190 : 0 : dom_tree_to_days_data (xmlNodePtr node, struct billterm_pdata* pdata)
191 : : {
192 : : gboolean successful;
193 : :
194 : 0 : successful = dom_tree_generic_parse (node, days_data_handlers_v2, pdata);
195 : :
196 : 0 : if (!successful)
197 : 0 : PERR ("failed to parse billing term days data");
198 : :
199 : 0 : return successful;
200 : : }
201 : :
202 : : /***********************************************************************/
203 : :
204 : : static gboolean
205 : 0 : prox_dueday_handler (xmlNodePtr node, gpointer billterm_pdata)
206 : : {
207 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
208 : 0 : return set_int (node, pdata->term, gncBillTermSetDueDays);
209 : : }
210 : :
211 : : static gboolean
212 : 0 : prox_discday_handler (xmlNodePtr node, gpointer billterm_pdata)
213 : : {
214 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
215 : 0 : return set_int (node, pdata->term, gncBillTermSetDiscountDays);
216 : : }
217 : :
218 : : static gboolean
219 : 0 : prox_discount_handler (xmlNodePtr node, gpointer billterm_pdata)
220 : : {
221 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
222 : 0 : return set_numeric (node, pdata->term, gncBillTermSetDiscount);
223 : : }
224 : :
225 : : static gboolean
226 : 0 : prox_cutoff_handler (xmlNodePtr node, gpointer billterm_pdata)
227 : : {
228 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
229 : 0 : return set_int (node, pdata->term, gncBillTermSetCutoff);
230 : : }
231 : :
232 : : static struct dom_tree_handler prox_data_handlers_v2[] =
233 : : {
234 : : { prox_dueday_string, prox_dueday_handler, 0, 0 },
235 : : { prox_discday_string, prox_discday_handler, 0, 0 },
236 : : { prox_discount_string, prox_discount_handler, 0, 0 },
237 : : { prox_cutoff_string, prox_cutoff_handler, 0, 0 },
238 : : { NULL, 0, 0, 0 }
239 : : };
240 : :
241 : : static gboolean
242 : 0 : dom_tree_to_prox_data (xmlNodePtr node, struct billterm_pdata* pdata)
243 : : {
244 : : gboolean successful;
245 : :
246 : 0 : successful = dom_tree_generic_parse (node, prox_data_handlers_v2, pdata);
247 : :
248 : 0 : if (!successful)
249 : 0 : PERR ("failed to parse billing term prox data");
250 : :
251 : 0 : return successful;
252 : : }
253 : :
254 : : /***********************************************************************/
255 : :
256 : : static gboolean
257 : 0 : set_parent_child (xmlNodePtr node, struct billterm_pdata* pdata,
258 : : void (*func) (GncBillTerm*, GncBillTerm*))
259 : : {
260 : : GncBillTerm* term;
261 : :
262 : 0 : auto guid = dom_tree_to_guid (node);
263 : 0 : g_return_val_if_fail (guid, FALSE);
264 : 0 : term = gncBillTermLookup (pdata->book, &*guid);
265 : 0 : if (!term)
266 : : {
267 : 0 : term = gncBillTermCreate (pdata->book);
268 : 0 : gncBillTermBeginEdit (term);
269 : 0 : gncBillTermSetGUID (term, &*guid);
270 : 0 : gncBillTermCommitEdit (term);
271 : : }
272 : 0 : g_return_val_if_fail (term, FALSE);
273 : 0 : func (pdata->term, term);
274 : :
275 : 0 : return TRUE;
276 : : }
277 : :
278 : : static gboolean
279 : 0 : billterm_guid_handler (xmlNodePtr node, gpointer billterm_pdata)
280 : : {
281 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
282 : : GncBillTerm* term;
283 : :
284 : 0 : auto guid = dom_tree_to_guid (node);
285 : 0 : g_return_val_if_fail (guid, FALSE);
286 : 0 : term = gncBillTermLookup (pdata->book, &*guid);
287 : 0 : if (term)
288 : : {
289 : 0 : gncBillTermDestroy (pdata->term);
290 : 0 : pdata->term = term;
291 : 0 : gncBillTermBeginEdit (term);
292 : : }
293 : : else
294 : : {
295 : 0 : gncBillTermSetGUID (pdata->term, &*guid);
296 : : }
297 : :
298 : 0 : return TRUE;
299 : : }
300 : :
301 : : static gboolean
302 : 0 : billterm_name_handler (xmlNodePtr node, gpointer billterm_pdata)
303 : : {
304 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
305 : 0 : return apply_xmlnode_text (gncBillTermSetName, pdata->term, node);
306 : : }
307 : :
308 : : static gboolean
309 : 0 : billterm_desc_handler (xmlNodePtr node, gpointer billterm_pdata)
310 : : {
311 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
312 : 0 : return apply_xmlnode_text (gncBillTermSetDescription, pdata->term, node);
313 : : }
314 : :
315 : : static gboolean
316 : 0 : billterm_refcount_handler (xmlNodePtr node, gpointer billterm_pdata)
317 : : {
318 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
319 : : gint64 val;
320 : :
321 : 0 : dom_tree_to_integer (node, &val);
322 : 0 : gncBillTermSetRefcount (pdata->term, val);
323 : 0 : return TRUE;
324 : : }
325 : :
326 : : static gboolean
327 : 0 : billterm_invisible_handler (xmlNodePtr node, gpointer billterm_pdata)
328 : : {
329 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
330 : : gint64 val;
331 : :
332 : 0 : dom_tree_to_integer (node, &val);
333 : 0 : if (val)
334 : 0 : gncBillTermMakeInvisible (pdata->term);
335 : 0 : return TRUE;
336 : : }
337 : :
338 : : static gboolean
339 : 0 : billterm_parent_handler (xmlNodePtr node, gpointer billterm_pdata)
340 : : {
341 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
342 : 0 : return set_parent_child (node, pdata, gncBillTermSetParent);
343 : : }
344 : :
345 : : static gboolean
346 : 0 : billterm_child_handler (xmlNodePtr node, gpointer billterm_pdata)
347 : : {
348 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
349 : 0 : return set_parent_child (node, pdata, gncBillTermSetChild);
350 : : }
351 : :
352 : : static gboolean
353 : 0 : billterm_days_data_handler (xmlNodePtr node, gpointer billterm_pdata)
354 : : {
355 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
356 : :
357 : 0 : g_return_val_if_fail (node, FALSE);
358 : 0 : g_return_val_if_fail (gncBillTermGetType (pdata->term) == 0, FALSE);
359 : :
360 : 0 : gncBillTermSetType (pdata->term, GNC_TERM_TYPE_DAYS);
361 : 0 : return dom_tree_to_days_data (node, pdata);
362 : : }
363 : :
364 : : static gboolean
365 : 0 : billterm_prox_data_handler (xmlNodePtr node, gpointer billterm_pdata)
366 : : {
367 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
368 : :
369 : 0 : g_return_val_if_fail (node, FALSE);
370 : 0 : g_return_val_if_fail (gncBillTermGetType (pdata->term) == 0, FALSE);
371 : :
372 : 0 : gncBillTermSetType (pdata->term, GNC_TERM_TYPE_PROXIMO);
373 : 0 : return dom_tree_to_prox_data (node, pdata);
374 : : }
375 : :
376 : : static gboolean
377 : 0 : billterm_slots_handler (xmlNodePtr node, gpointer billterm_pdata)
378 : : {
379 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
380 : 0 : return dom_tree_create_instance_slots (node, QOF_INSTANCE (pdata->term));
381 : : }
382 : :
383 : : static struct dom_tree_handler billterm_handlers_v2[] =
384 : : {
385 : : { billterm_guid_string, billterm_guid_handler, 1, 0 },
386 : : { billterm_name_string, billterm_name_handler, 1, 0 },
387 : : { billterm_desc_string, billterm_desc_handler, 1, 0 },
388 : : { billterm_refcount_string, billterm_refcount_handler, 1, 0 },
389 : : { billterm_invisible_string, billterm_invisible_handler, 1, 0 },
390 : : { billterm_parent_string, billterm_parent_handler, 0, 0 },
391 : : { billterm_child_string, billterm_child_handler, 0, 0 },
392 : : { billterm_slots_string, billterm_slots_handler, 0, 0 },
393 : : { gnc_daystype_string, billterm_days_data_handler, 0, 0 },
394 : : { gnc_proximotype_string, billterm_prox_data_handler, 0, 0 },
395 : : { NULL, 0, 0, 0 }
396 : : };
397 : :
398 : : static GncBillTerm*
399 : 0 : dom_tree_to_billterm (xmlNodePtr node, QofBook* book)
400 : : {
401 : : struct billterm_pdata billterm_pdata;
402 : : gboolean successful;
403 : :
404 : 0 : billterm_pdata.term = gncBillTermCreate (book);
405 : 0 : billterm_pdata.book = book;
406 : 0 : gncBillTermBeginEdit (billterm_pdata.term);
407 : :
408 : 0 : successful = dom_tree_generic_parse (node, billterm_handlers_v2,
409 : : &billterm_pdata);
410 : :
411 : 0 : if (successful)
412 : : {
413 : 0 : gncBillTermCommitEdit (billterm_pdata.term);
414 : : }
415 : : else
416 : : {
417 : 0 : PERR ("failed to parse billing term tree");
418 : 0 : gncBillTermDestroy (billterm_pdata.term);
419 : 0 : billterm_pdata.term = NULL;
420 : : }
421 : :
422 : 0 : return billterm_pdata.term;
423 : : }
424 : :
425 : : static gboolean
426 : 0 : gnc_billterm_end_handler (gpointer data_for_children,
427 : : GSList* data_from_children, GSList* sibling_data,
428 : : gpointer parent_data, gpointer global_data,
429 : : gpointer* result, const gchar* tag)
430 : : {
431 : : GncBillTerm* term;
432 : 0 : xmlNodePtr tree = (xmlNodePtr)data_for_children;
433 : 0 : gxpf_data* gdata = (gxpf_data*)global_data;
434 : 0 : QofBook* book = static_cast<decltype (book)> (gdata->bookdata);
435 : :
436 : :
437 : 0 : if (parent_data)
438 : : {
439 : 0 : return TRUE;
440 : : }
441 : :
442 : : /* OK. For some messed up reason this is getting called again with a
443 : : NULL tag. So we ignore those cases */
444 : 0 : if (!tag)
445 : : {
446 : 0 : return TRUE;
447 : : }
448 : :
449 : 0 : g_return_val_if_fail (tree, FALSE);
450 : :
451 : 0 : term = dom_tree_to_billterm (tree, book);
452 : 0 : if (term != NULL)
453 : : {
454 : 0 : gdata->cb (tag, gdata->parsedata, term);
455 : : }
456 : :
457 : 0 : xmlFreeNode (tree);
458 : :
459 : 0 : return term != NULL;
460 : : }
461 : :
462 : : static sixtp*
463 : 22 : billterm_sixtp_parser_create (void)
464 : : {
465 : 22 : return sixtp_dom_parser_new (gnc_billterm_end_handler, NULL, NULL);
466 : : }
467 : :
468 : : static void
469 : 0 : do_count (QofInstance* term_p, gpointer count_p)
470 : : {
471 : 0 : int* count = static_cast<decltype (count)> (count_p);
472 : 0 : (*count)++;
473 : 0 : }
474 : :
475 : : static int
476 : 4 : billterm_get_count (QofBook* book)
477 : : {
478 : 4 : int count = 0;
479 : 4 : qof_object_foreach (_GNC_MOD_NAME, book, do_count, (gpointer) &count);
480 : 4 : return count;
481 : : }
482 : :
483 : : static void
484 : 0 : xml_add_billterm (QofInstance* term_p, gpointer out_p)
485 : : {
486 : : xmlNodePtr node;
487 : 0 : GncBillTerm* term = (GncBillTerm*) term_p;
488 : 0 : FILE* out = static_cast<decltype (out)> (out_p);
489 : :
490 : 0 : if (ferror (out))
491 : 0 : return;
492 : :
493 : 0 : node = billterm_dom_tree_create (term);
494 : 0 : xmlElemDump (out, NULL, node);
495 : 0 : xmlFreeNode (node);
496 : 0 : if (ferror (out) || fprintf (out, "\n") < 0)
497 : 0 : return;
498 : : }
499 : :
500 : : static gboolean
501 : 4 : billterm_write (FILE* out, QofBook* book)
502 : : {
503 : 4 : qof_object_foreach_sorted (_GNC_MOD_NAME, book, xml_add_billterm,
504 : : (gpointer) out);
505 : 4 : return ferror (out) == 0;
506 : : }
507 : :
508 : : static gboolean
509 : 0 : billterm_is_grandchild (GncBillTerm* term)
510 : : {
511 : 0 : return (gncBillTermGetParent (gncBillTermGetParent (term)) != NULL);
512 : : }
513 : :
514 : : static GncBillTerm*
515 : 0 : billterm_find_senior (GncBillTerm* term)
516 : : {
517 : 0 : GncBillTerm* temp, *parent, *gp = NULL;
518 : :
519 : 0 : temp = term;
520 : : do
521 : : {
522 : : /* See if "temp" is a grandchild */
523 : 0 : parent = gncBillTermGetParent (temp);
524 : 0 : if (!parent)
525 : 0 : break;
526 : 0 : gp = gncBillTermGetParent (parent);
527 : 0 : if (!gp)
528 : 0 : break;
529 : :
530 : : /* Yep, this is a grandchild. Move up one generation and try again */
531 : 0 : temp = parent;
532 : : }
533 : : while (TRUE);
534 : :
535 : : /* Ok, at this point temp points to the most senior child and parent
536 : : * should point to the top billterm (and gp should be NULL). If
537 : : * parent is NULL then we are the most senior child (and have no
538 : : * children), so do nothing. If temp == term then there is no
539 : : * grandparent, so do nothing.
540 : : *
541 : : * Do something if parent != NULL && temp != term
542 : : */
543 : 0 : g_assert (gp == NULL);
544 : :
545 : : /* return the most senior term */
546 : 0 : return temp;
547 : : }
548 : :
549 : : /* build a list of bill terms that are grandchildren or bogus (empty entry list). */
550 : : static void
551 : 0 : billterm_scrub_cb (QofInstance* term_p, gpointer list_p)
552 : : {
553 : 0 : GncBillTerm* term = GNC_BILLTERM (term_p);
554 : 0 : GList** list = static_cast<decltype (list)> (list_p);
555 : :
556 : 0 : if (billterm_is_grandchild (term))
557 : : {
558 : 0 : *list = g_list_prepend (*list, term);
559 : :
560 : : }
561 : 0 : else if (!gncBillTermGetType (term))
562 : : {
563 : 0 : GncBillTerm* t = gncBillTermGetParent (term);
564 : 0 : if (t)
565 : : {
566 : : /* Fix up the broken "copy" function */
567 : : gchar guidstr[GUID_ENCODING_LENGTH + 1];
568 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), guidstr);
569 : 0 : PWARN ("Fixing broken child billterm: %s", guidstr);
570 : :
571 : 0 : gncBillTermBeginEdit (term);
572 : 0 : gncBillTermSetType (term, gncBillTermGetType (t));
573 : 0 : gncBillTermSetDueDays (term, gncBillTermGetDueDays (t));
574 : 0 : gncBillTermSetDiscountDays (term, gncBillTermGetDiscountDays (t));
575 : 0 : gncBillTermSetDiscount (term, gncBillTermGetDiscount (t));
576 : 0 : gncBillTermSetCutoff (term, gncBillTermGetCutoff (t));
577 : 0 : gncBillTermCommitEdit (term);
578 : :
579 : : }
580 : : else
581 : : {
582 : : /* No parent? Must be a standalone */
583 : 0 : *list = g_list_prepend (*list, term);
584 : : }
585 : : }
586 : 0 : }
587 : :
588 : : /* for each invoice, check the bill terms. If the bill terms are
589 : : * grandchildren, then fix them to point to the most senior child
590 : : */
591 : : static void
592 : 4 : billterm_scrub_invoices (QofInstance* invoice_p, gpointer ht_p)
593 : : {
594 : 4 : GHashTable* ht = static_cast<decltype (ht)> (ht_p);
595 : 4 : GncInvoice* invoice = GNC_INVOICE (invoice_p);
596 : : GncBillTerm* term, *new_bt;
597 : : gint32 count;
598 : :
599 : 4 : term = gncInvoiceGetTerms (invoice);
600 : 4 : if (term)
601 : : {
602 : 0 : if (billterm_is_grandchild (term))
603 : : {
604 : : gchar guidstr[GUID_ENCODING_LENGTH + 1];
605 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (invoice)), guidstr);
606 : 0 : PWARN ("Fixing i-billterm on invoice %s\n", guidstr);
607 : 0 : new_bt = billterm_find_senior (term);
608 : 0 : gncInvoiceBeginEdit (invoice);
609 : 0 : gncInvoiceSetTerms (invoice, new_bt);
610 : 0 : gncInvoiceCommitEdit (invoice);
611 : 0 : term = new_bt;
612 : : }
613 : 0 : if (term)
614 : : {
615 : 0 : count = GPOINTER_TO_INT (g_hash_table_lookup (ht, term));
616 : 0 : count++;
617 : 0 : g_hash_table_insert (ht, term, GINT_TO_POINTER (count));
618 : : }
619 : : }
620 : 4 : }
621 : :
622 : : static void
623 : 1 : billterm_scrub_cust (QofInstance* cust_p, gpointer ht_p)
624 : : {
625 : 1 : GHashTable* ht = static_cast<decltype (ht)> (ht_p);
626 : 1 : GncCustomer* cust = GNC_CUSTOMER (cust_p);
627 : : GncBillTerm* term;
628 : : gint32 count;
629 : :
630 : 1 : term = gncCustomerGetTerms (cust);
631 : 1 : if (term)
632 : : {
633 : 0 : count = GPOINTER_TO_INT (g_hash_table_lookup (ht, term));
634 : 0 : count++;
635 : 0 : g_hash_table_insert (ht, term, GINT_TO_POINTER (count));
636 : 0 : if (billterm_is_grandchild (term))
637 : : {
638 : : gchar custstr[GUID_ENCODING_LENGTH + 1];
639 : : gchar termstr[GUID_ENCODING_LENGTH + 1];
640 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (cust)), custstr);
641 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), termstr);
642 : 0 : PWARN ("customer %s has grandchild billterm %s\n", custstr, termstr);
643 : : }
644 : : }
645 : 1 : }
646 : :
647 : : static void
648 : 3 : billterm_scrub_vendor (QofInstance* vendor_p, gpointer ht_p)
649 : : {
650 : 3 : GHashTable* ht = static_cast<decltype (ht)> (ht_p);
651 : 3 : GncVendor* vendor = GNC_VENDOR (vendor_p);
652 : : GncBillTerm* term;
653 : : gint32 count;
654 : :
655 : 3 : term = gncVendorGetTerms (vendor);
656 : 3 : if (term)
657 : : {
658 : 0 : count = GPOINTER_TO_INT (g_hash_table_lookup (ht, term));
659 : 0 : count++;
660 : 0 : g_hash_table_insert (ht, term, GINT_TO_POINTER (count));
661 : 0 : if (billterm_is_grandchild (term))
662 : : {
663 : : gchar vendstr[GUID_ENCODING_LENGTH + 1];
664 : : gchar termstr[GUID_ENCODING_LENGTH + 1];
665 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (vendor)), vendstr);
666 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), termstr);
667 : 0 : PWARN ("vendor %s has grandchild billterm %s\n", vendstr, termstr);
668 : : }
669 : : }
670 : 3 : }
671 : :
672 : : static void
673 : 0 : billterm_reset_refcount (gpointer key, gpointer value, gpointer notused)
674 : : {
675 : 0 : GncBillTerm* term = static_cast<decltype (term)> (key);
676 : 0 : gint32 count = GPOINTER_TO_INT (value);
677 : :
678 : 0 : if (count != gncBillTermGetRefcount (term) && !gncBillTermGetInvisible (term))
679 : : {
680 : : gchar termstr[GUID_ENCODING_LENGTH + 1];
681 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), termstr);
682 : 0 : PWARN ("Fixing refcount on billterm %s (%" G_GINT64_FORMAT " -> %d)\n",
683 : : termstr, gncBillTermGetRefcount (term), count);
684 : 0 : gncBillTermSetRefcount (term, count);
685 : : }
686 : 0 : }
687 : :
688 : : static void
689 : 22 : billterm_scrub (QofBook* book)
690 : : {
691 : 22 : GList* list = NULL;
692 : : GList* node;
693 : : GncBillTerm* parent, *term;
694 : 22 : GHashTable* ht = g_hash_table_new (g_direct_hash, g_direct_equal);
695 : :
696 : 22 : DEBUG ("scrubbing billterms...");
697 : 22 : qof_object_foreach (GNC_ID_INVOICE, book, billterm_scrub_invoices, ht);
698 : 22 : qof_object_foreach (GNC_ID_CUSTOMER, book, billterm_scrub_cust, ht);
699 : 22 : qof_object_foreach (GNC_ID_VENDOR, book, billterm_scrub_vendor, ht);
700 : 22 : qof_object_foreach (GNC_ID_BILLTERM, book, billterm_scrub_cb, &list);
701 : :
702 : : /* destroy the list of "grandchildren" bill terms */
703 : 22 : for (node = list; node; node = node->next)
704 : : {
705 : : gchar termstr[GUID_ENCODING_LENGTH + 1];
706 : 0 : term = static_cast<decltype (term)> (node->data);
707 : :
708 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), termstr);
709 : 0 : PWARN ("deleting grandchild billterm: %s\n", termstr);
710 : :
711 : : /* Make sure the parent has no children */
712 : 0 : parent = gncBillTermGetParent (term);
713 : 0 : gncBillTermSetChild (parent, NULL);
714 : :
715 : : /* Destroy this bill term */
716 : 0 : gncBillTermBeginEdit (term);
717 : 0 : gncBillTermDestroy (term);
718 : : }
719 : :
720 : : /* reset the refcounts as necessary */
721 : 22 : g_hash_table_foreach (ht, billterm_reset_refcount, NULL);
722 : :
723 : 22 : g_list_free (list);
724 : 22 : g_hash_table_destroy (ht);
725 : 22 : }
726 : :
727 : : static gboolean
728 : 4 : billterm_ns (FILE* out)
729 : : {
730 : 4 : g_return_val_if_fail (out, FALSE);
731 : : return
732 : 4 : gnc_xml2_write_namespace_decl (out, "billterm")
733 : 4 : && gnc_xml2_write_namespace_decl (out, "bt-days")
734 : 8 : && gnc_xml2_write_namespace_decl (out, "bt-prox");
735 : : }
736 : :
737 : : void
738 : 15 : gnc_billterm_xml_initialize (void)
739 : : {
740 : : static GncXmlDataType_t be_data =
741 : : {
742 : : GNC_FILE_BACKEND_VERS,
743 : : gnc_billterm_string,
744 : : billterm_sixtp_parser_create,
745 : : NULL, /* add_item */
746 : : billterm_get_count,
747 : : billterm_write,
748 : : billterm_scrub,
749 : : billterm_ns,
750 : : };
751 : :
752 : 15 : gnc_xml_register_backend(be_data);
753 : 15 : }
754 : :
755 : : GncBillTerm*
756 : 0 : gnc_billterm_xml_find_or_create (QofBook* book, GncGUID* guid)
757 : : {
758 : : GncBillTerm* term;
759 : : gchar guidstr[GUID_ENCODING_LENGTH + 1];
760 : :
761 : 0 : guid_to_string_buff (guid, guidstr);
762 : 0 : g_return_val_if_fail (book, NULL);
763 : 0 : g_return_val_if_fail (guid, NULL);
764 : 0 : term = gncBillTermLookup (book, guid);
765 : 0 : DEBUG ("looking for billterm %s, found %p", guidstr, term);
766 : 0 : if (!term)
767 : : {
768 : 0 : term = gncBillTermCreate (book);
769 : 0 : gncBillTermBeginEdit (term);
770 : 0 : gncBillTermSetGUID (term, guid);
771 : 0 : gncBillTermCommitEdit (term);
772 : 0 : DEBUG ("Created term: %p", term);
773 : : }
774 : : else
775 : 0 : gncBillTermDecRef (term);
776 : :
777 : 0 : return term;
778 : : }
|