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 : : GncGUID* guid;
261 : : GncBillTerm* term;
262 : :
263 : 0 : guid = dom_tree_to_guid (node);
264 : 0 : g_return_val_if_fail (guid, FALSE);
265 : 0 : term = gncBillTermLookup (pdata->book, guid);
266 : 0 : if (!term)
267 : : {
268 : 0 : term = gncBillTermCreate (pdata->book);
269 : 0 : gncBillTermBeginEdit (term);
270 : 0 : gncBillTermSetGUID (term, guid);
271 : 0 : gncBillTermCommitEdit (term);
272 : : }
273 : 0 : guid_free (guid);
274 : 0 : g_return_val_if_fail (term, FALSE);
275 : 0 : func (pdata->term, term);
276 : :
277 : 0 : return TRUE;
278 : : }
279 : :
280 : : static gboolean
281 : 0 : set_string (xmlNodePtr node, GncBillTerm* term,
282 : : void (*func) (GncBillTerm*, const char*))
283 : : {
284 : 0 : char* txt = dom_tree_to_text (node);
285 : 0 : g_return_val_if_fail (txt, FALSE);
286 : 0 : func (term, txt);
287 : 0 : g_free (txt);
288 : 0 : return TRUE;
289 : : }
290 : :
291 : : static gboolean
292 : 0 : billterm_guid_handler (xmlNodePtr node, gpointer billterm_pdata)
293 : : {
294 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
295 : : GncGUID* guid;
296 : : GncBillTerm* term;
297 : :
298 : 0 : guid = dom_tree_to_guid (node);
299 : 0 : g_return_val_if_fail (guid, FALSE);
300 : 0 : term = gncBillTermLookup (pdata->book, guid);
301 : 0 : if (term)
302 : : {
303 : 0 : gncBillTermDestroy (pdata->term);
304 : 0 : pdata->term = term;
305 : 0 : gncBillTermBeginEdit (term);
306 : : }
307 : : else
308 : : {
309 : 0 : gncBillTermSetGUID (pdata->term, guid);
310 : : }
311 : :
312 : 0 : guid_free (guid);
313 : :
314 : 0 : return TRUE;
315 : : }
316 : :
317 : : static gboolean
318 : 0 : billterm_name_handler (xmlNodePtr node, gpointer billterm_pdata)
319 : : {
320 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
321 : 0 : return set_string (node, pdata->term, gncBillTermSetName);
322 : : }
323 : :
324 : : static gboolean
325 : 0 : billterm_desc_handler (xmlNodePtr node, gpointer billterm_pdata)
326 : : {
327 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
328 : 0 : return set_string (node, pdata->term, gncBillTermSetDescription);
329 : : }
330 : :
331 : : static gboolean
332 : 0 : billterm_refcount_handler (xmlNodePtr node, gpointer billterm_pdata)
333 : : {
334 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
335 : : gint64 val;
336 : :
337 : 0 : dom_tree_to_integer (node, &val);
338 : 0 : gncBillTermSetRefcount (pdata->term, val);
339 : 0 : return TRUE;
340 : : }
341 : :
342 : : static gboolean
343 : 0 : billterm_invisible_handler (xmlNodePtr node, gpointer billterm_pdata)
344 : : {
345 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
346 : : gint64 val;
347 : :
348 : 0 : dom_tree_to_integer (node, &val);
349 : 0 : if (val)
350 : 0 : gncBillTermMakeInvisible (pdata->term);
351 : 0 : return TRUE;
352 : : }
353 : :
354 : : static gboolean
355 : 0 : billterm_parent_handler (xmlNodePtr node, gpointer billterm_pdata)
356 : : {
357 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
358 : 0 : return set_parent_child (node, pdata, gncBillTermSetParent);
359 : : }
360 : :
361 : : static gboolean
362 : 0 : billterm_child_handler (xmlNodePtr node, gpointer billterm_pdata)
363 : : {
364 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
365 : 0 : return set_parent_child (node, pdata, gncBillTermSetChild);
366 : : }
367 : :
368 : : static gboolean
369 : 0 : billterm_days_data_handler (xmlNodePtr node, gpointer billterm_pdata)
370 : : {
371 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
372 : :
373 : 0 : g_return_val_if_fail (node, FALSE);
374 : 0 : g_return_val_if_fail (gncBillTermGetType (pdata->term) == 0, FALSE);
375 : :
376 : 0 : gncBillTermSetType (pdata->term, GNC_TERM_TYPE_DAYS);
377 : 0 : return dom_tree_to_days_data (node, pdata);
378 : : }
379 : :
380 : : static gboolean
381 : 0 : billterm_prox_data_handler (xmlNodePtr node, gpointer billterm_pdata)
382 : : {
383 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
384 : :
385 : 0 : g_return_val_if_fail (node, FALSE);
386 : 0 : g_return_val_if_fail (gncBillTermGetType (pdata->term) == 0, FALSE);
387 : :
388 : 0 : gncBillTermSetType (pdata->term, GNC_TERM_TYPE_PROXIMO);
389 : 0 : return dom_tree_to_prox_data (node, pdata);
390 : : }
391 : :
392 : : static gboolean
393 : 0 : billterm_slots_handler (xmlNodePtr node, gpointer billterm_pdata)
394 : : {
395 : 0 : struct billterm_pdata* pdata = static_cast<decltype (pdata)> (billterm_pdata);
396 : 0 : return dom_tree_create_instance_slots (node, QOF_INSTANCE (pdata->term));
397 : : }
398 : :
399 : : static struct dom_tree_handler billterm_handlers_v2[] =
400 : : {
401 : : { billterm_guid_string, billterm_guid_handler, 1, 0 },
402 : : { billterm_name_string, billterm_name_handler, 1, 0 },
403 : : { billterm_desc_string, billterm_desc_handler, 1, 0 },
404 : : { billterm_refcount_string, billterm_refcount_handler, 1, 0 },
405 : : { billterm_invisible_string, billterm_invisible_handler, 1, 0 },
406 : : { billterm_parent_string, billterm_parent_handler, 0, 0 },
407 : : { billterm_child_string, billterm_child_handler, 0, 0 },
408 : : { billterm_slots_string, billterm_slots_handler, 0, 0 },
409 : : { gnc_daystype_string, billterm_days_data_handler, 0, 0 },
410 : : { gnc_proximotype_string, billterm_prox_data_handler, 0, 0 },
411 : : { NULL, 0, 0, 0 }
412 : : };
413 : :
414 : : static GncBillTerm*
415 : 0 : dom_tree_to_billterm (xmlNodePtr node, QofBook* book)
416 : : {
417 : : struct billterm_pdata billterm_pdata;
418 : : gboolean successful;
419 : :
420 : 0 : billterm_pdata.term = gncBillTermCreate (book);
421 : 0 : billterm_pdata.book = book;
422 : 0 : gncBillTermBeginEdit (billterm_pdata.term);
423 : :
424 : 0 : successful = dom_tree_generic_parse (node, billterm_handlers_v2,
425 : : &billterm_pdata);
426 : :
427 : 0 : if (successful)
428 : : {
429 : 0 : gncBillTermCommitEdit (billterm_pdata.term);
430 : : }
431 : : else
432 : : {
433 : 0 : PERR ("failed to parse billing term tree");
434 : 0 : gncBillTermDestroy (billterm_pdata.term);
435 : 0 : billterm_pdata.term = NULL;
436 : : }
437 : :
438 : 0 : return billterm_pdata.term;
439 : : }
440 : :
441 : : static gboolean
442 : 0 : gnc_billterm_end_handler (gpointer data_for_children,
443 : : GSList* data_from_children, GSList* sibling_data,
444 : : gpointer parent_data, gpointer global_data,
445 : : gpointer* result, const gchar* tag)
446 : : {
447 : : GncBillTerm* term;
448 : 0 : xmlNodePtr tree = (xmlNodePtr)data_for_children;
449 : 0 : gxpf_data* gdata = (gxpf_data*)global_data;
450 : 0 : QofBook* book = static_cast<decltype (book)> (gdata->bookdata);
451 : :
452 : :
453 : 0 : if (parent_data)
454 : : {
455 : 0 : return TRUE;
456 : : }
457 : :
458 : : /* OK. For some messed up reason this is getting called again with a
459 : : NULL tag. So we ignore those cases */
460 : 0 : if (!tag)
461 : : {
462 : 0 : return TRUE;
463 : : }
464 : :
465 : 0 : g_return_val_if_fail (tree, FALSE);
466 : :
467 : 0 : term = dom_tree_to_billterm (tree, book);
468 : 0 : if (term != NULL)
469 : : {
470 : 0 : gdata->cb (tag, gdata->parsedata, term);
471 : : }
472 : :
473 : 0 : xmlFreeNode (tree);
474 : :
475 : 0 : return term != NULL;
476 : : }
477 : :
478 : : static sixtp*
479 : 21 : billterm_sixtp_parser_create (void)
480 : : {
481 : 21 : return sixtp_dom_parser_new (gnc_billterm_end_handler, NULL, NULL);
482 : : }
483 : :
484 : : static void
485 : 0 : do_count (QofInstance* term_p, gpointer count_p)
486 : : {
487 : 0 : int* count = static_cast<decltype (count)> (count_p);
488 : 0 : (*count)++;
489 : 0 : }
490 : :
491 : : static int
492 : 4 : billterm_get_count (QofBook* book)
493 : : {
494 : 4 : int count = 0;
495 : 4 : qof_object_foreach (_GNC_MOD_NAME, book, do_count, (gpointer) &count);
496 : 4 : return count;
497 : : }
498 : :
499 : : static void
500 : 0 : xml_add_billterm (QofInstance* term_p, gpointer out_p)
501 : : {
502 : : xmlNodePtr node;
503 : 0 : GncBillTerm* term = (GncBillTerm*) term_p;
504 : 0 : FILE* out = static_cast<decltype (out)> (out_p);
505 : :
506 : 0 : if (ferror (out))
507 : 0 : return;
508 : :
509 : 0 : node = billterm_dom_tree_create (term);
510 : 0 : xmlElemDump (out, NULL, node);
511 : 0 : xmlFreeNode (node);
512 : 0 : if (ferror (out) || fprintf (out, "\n") < 0)
513 : 0 : return;
514 : : }
515 : :
516 : : static gboolean
517 : 4 : billterm_write (FILE* out, QofBook* book)
518 : : {
519 : 4 : qof_object_foreach_sorted (_GNC_MOD_NAME, book, xml_add_billterm,
520 : : (gpointer) out);
521 : 4 : return ferror (out) == 0;
522 : : }
523 : :
524 : : static gboolean
525 : 0 : billterm_is_grandchild (GncBillTerm* term)
526 : : {
527 : 0 : return (gncBillTermGetParent (gncBillTermGetParent (term)) != NULL);
528 : : }
529 : :
530 : : static GncBillTerm*
531 : 0 : billterm_find_senior (GncBillTerm* term)
532 : : {
533 : 0 : GncBillTerm* temp, *parent, *gp = NULL;
534 : :
535 : 0 : temp = term;
536 : : do
537 : : {
538 : : /* See if "temp" is a grandchild */
539 : 0 : parent = gncBillTermGetParent (temp);
540 : 0 : if (!parent)
541 : 0 : break;
542 : 0 : gp = gncBillTermGetParent (parent);
543 : 0 : if (!gp)
544 : 0 : break;
545 : :
546 : : /* Yep, this is a grandchild. Move up one generation and try again */
547 : 0 : temp = parent;
548 : : }
549 : : while (TRUE);
550 : :
551 : : /* Ok, at this point temp points to the most senior child and parent
552 : : * should point to the top billterm (and gp should be NULL). If
553 : : * parent is NULL then we are the most senior child (and have no
554 : : * children), so do nothing. If temp == term then there is no
555 : : * grandparent, so do nothing.
556 : : *
557 : : * Do something if parent != NULL && temp != term
558 : : */
559 : 0 : g_assert (gp == NULL);
560 : :
561 : : /* return the most senior term */
562 : 0 : return temp;
563 : : }
564 : :
565 : : /* build a list of bill terms that are grandchildren or bogus (empty entry list). */
566 : : static void
567 : 0 : billterm_scrub_cb (QofInstance* term_p, gpointer list_p)
568 : : {
569 : 0 : GncBillTerm* term = GNC_BILLTERM (term_p);
570 : 0 : GList** list = static_cast<decltype (list)> (list_p);
571 : :
572 : 0 : if (billterm_is_grandchild (term))
573 : : {
574 : 0 : *list = g_list_prepend (*list, term);
575 : :
576 : : }
577 : 0 : else if (!gncBillTermGetType (term))
578 : : {
579 : 0 : GncBillTerm* t = gncBillTermGetParent (term);
580 : 0 : if (t)
581 : : {
582 : : /* Fix up the broken "copy" function */
583 : : gchar guidstr[GUID_ENCODING_LENGTH + 1];
584 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), guidstr);
585 : 0 : PWARN ("Fixing broken child billterm: %s", guidstr);
586 : :
587 : 0 : gncBillTermBeginEdit (term);
588 : 0 : gncBillTermSetType (term, gncBillTermGetType (t));
589 : 0 : gncBillTermSetDueDays (term, gncBillTermGetDueDays (t));
590 : 0 : gncBillTermSetDiscountDays (term, gncBillTermGetDiscountDays (t));
591 : 0 : gncBillTermSetDiscount (term, gncBillTermGetDiscount (t));
592 : 0 : gncBillTermSetCutoff (term, gncBillTermGetCutoff (t));
593 : 0 : gncBillTermCommitEdit (term);
594 : :
595 : : }
596 : : else
597 : : {
598 : : /* No parent? Must be a standalone */
599 : 0 : *list = g_list_prepend (*list, term);
600 : : }
601 : : }
602 : 0 : }
603 : :
604 : : /* for each invoice, check the bill terms. If the bill terms are
605 : : * grandchildren, then fix them to point to the most senior child
606 : : */
607 : : static void
608 : 3 : billterm_scrub_invoices (QofInstance* invoice_p, gpointer ht_p)
609 : : {
610 : 3 : GHashTable* ht = static_cast<decltype (ht)> (ht_p);
611 : 3 : GncInvoice* invoice = GNC_INVOICE (invoice_p);
612 : : GncBillTerm* term, *new_bt;
613 : : gint32 count;
614 : :
615 : 3 : term = gncInvoiceGetTerms (invoice);
616 : 3 : if (term)
617 : : {
618 : 0 : if (billterm_is_grandchild (term))
619 : : {
620 : : gchar guidstr[GUID_ENCODING_LENGTH + 1];
621 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (invoice)), guidstr);
622 : 0 : PWARN ("Fixing i-billterm on invoice %s\n", guidstr);
623 : 0 : new_bt = billterm_find_senior (term);
624 : 0 : gncInvoiceBeginEdit (invoice);
625 : 0 : gncInvoiceSetTerms (invoice, new_bt);
626 : 0 : gncInvoiceCommitEdit (invoice);
627 : 0 : term = new_bt;
628 : : }
629 : 0 : if (term)
630 : : {
631 : 0 : count = GPOINTER_TO_INT (g_hash_table_lookup (ht, term));
632 : 0 : count++;
633 : 0 : g_hash_table_insert (ht, term, GINT_TO_POINTER (count));
634 : : }
635 : : }
636 : 3 : }
637 : :
638 : : static void
639 : 0 : billterm_scrub_cust (QofInstance* cust_p, gpointer ht_p)
640 : : {
641 : 0 : GHashTable* ht = static_cast<decltype (ht)> (ht_p);
642 : 0 : GncCustomer* cust = GNC_CUSTOMER (cust_p);
643 : : GncBillTerm* term;
644 : : gint32 count;
645 : :
646 : 0 : term = gncCustomerGetTerms (cust);
647 : 0 : if (term)
648 : : {
649 : 0 : count = GPOINTER_TO_INT (g_hash_table_lookup (ht, term));
650 : 0 : count++;
651 : 0 : g_hash_table_insert (ht, term, GINT_TO_POINTER (count));
652 : 0 : if (billterm_is_grandchild (term))
653 : : {
654 : : gchar custstr[GUID_ENCODING_LENGTH + 1];
655 : : gchar termstr[GUID_ENCODING_LENGTH + 1];
656 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (cust)), custstr);
657 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), termstr);
658 : 0 : PWARN ("customer %s has grandchild billterm %s\n", custstr, termstr);
659 : : }
660 : : }
661 : 0 : }
662 : :
663 : : static void
664 : 3 : billterm_scrub_vendor (QofInstance* vendor_p, gpointer ht_p)
665 : : {
666 : 3 : GHashTable* ht = static_cast<decltype (ht)> (ht_p);
667 : 3 : GncVendor* vendor = GNC_VENDOR (vendor_p);
668 : : GncBillTerm* term;
669 : : gint32 count;
670 : :
671 : 3 : term = gncVendorGetTerms (vendor);
672 : 3 : if (term)
673 : : {
674 : 0 : count = GPOINTER_TO_INT (g_hash_table_lookup (ht, term));
675 : 0 : count++;
676 : 0 : g_hash_table_insert (ht, term, GINT_TO_POINTER (count));
677 : 0 : if (billterm_is_grandchild (term))
678 : : {
679 : : gchar vendstr[GUID_ENCODING_LENGTH + 1];
680 : : gchar termstr[GUID_ENCODING_LENGTH + 1];
681 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (vendor)), vendstr);
682 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), termstr);
683 : 0 : PWARN ("vendor %s has grandchild billterm %s\n", vendstr, termstr);
684 : : }
685 : : }
686 : 3 : }
687 : :
688 : : static void
689 : 0 : billterm_reset_refcount (gpointer key, gpointer value, gpointer notused)
690 : : {
691 : 0 : GncBillTerm* term = static_cast<decltype (term)> (key);
692 : 0 : gint32 count = GPOINTER_TO_INT (value);
693 : :
694 : 0 : if (count != gncBillTermGetRefcount (term) && !gncBillTermGetInvisible (term))
695 : : {
696 : : gchar termstr[GUID_ENCODING_LENGTH + 1];
697 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), termstr);
698 : 0 : PWARN ("Fixing refcount on billterm %s (%" G_GINT64_FORMAT " -> %d)\n",
699 : : termstr, gncBillTermGetRefcount (term), count);
700 : 0 : gncBillTermSetRefcount (term, count);
701 : : }
702 : 0 : }
703 : :
704 : : static void
705 : 21 : billterm_scrub (QofBook* book)
706 : : {
707 : 21 : GList* list = NULL;
708 : : GList* node;
709 : : GncBillTerm* parent, *term;
710 : 21 : GHashTable* ht = g_hash_table_new (g_direct_hash, g_direct_equal);
711 : :
712 : 21 : DEBUG ("scrubbing billterms...");
713 : 21 : qof_object_foreach (GNC_ID_INVOICE, book, billterm_scrub_invoices, ht);
714 : 21 : qof_object_foreach (GNC_ID_CUSTOMER, book, billterm_scrub_cust, ht);
715 : 21 : qof_object_foreach (GNC_ID_VENDOR, book, billterm_scrub_vendor, ht);
716 : 21 : qof_object_foreach (GNC_ID_BILLTERM, book, billterm_scrub_cb, &list);
717 : :
718 : : /* destroy the list of "grandchildren" bill terms */
719 : 21 : for (node = list; node; node = node->next)
720 : : {
721 : : gchar termstr[GUID_ENCODING_LENGTH + 1];
722 : 0 : term = static_cast<decltype (term)> (node->data);
723 : :
724 : 0 : guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (term)), termstr);
725 : 0 : PWARN ("deleting grandchild billterm: %s\n", termstr);
726 : :
727 : : /* Make sure the parent has no children */
728 : 0 : parent = gncBillTermGetParent (term);
729 : 0 : gncBillTermSetChild (parent, NULL);
730 : :
731 : : /* Destroy this bill term */
732 : 0 : gncBillTermBeginEdit (term);
733 : 0 : gncBillTermDestroy (term);
734 : : }
735 : :
736 : : /* reset the refcounts as necessary */
737 : 21 : g_hash_table_foreach (ht, billterm_reset_refcount, NULL);
738 : :
739 : 21 : g_list_free (list);
740 : 21 : g_hash_table_destroy (ht);
741 : 21 : }
742 : :
743 : : static gboolean
744 : 4 : billterm_ns (FILE* out)
745 : : {
746 : 4 : g_return_val_if_fail (out, FALSE);
747 : : return
748 : 4 : gnc_xml2_write_namespace_decl (out, "billterm")
749 : 4 : && gnc_xml2_write_namespace_decl (out, "bt-days")
750 : 8 : && gnc_xml2_write_namespace_decl (out, "bt-prox");
751 : : }
752 : :
753 : : void
754 : 61 : gnc_billterm_xml_initialize (void)
755 : : {
756 : : static GncXmlDataType_t be_data =
757 : : {
758 : : GNC_FILE_BACKEND_VERS,
759 : : gnc_billterm_string,
760 : : billterm_sixtp_parser_create,
761 : : NULL, /* add_item */
762 : : billterm_get_count,
763 : : billterm_write,
764 : : billterm_scrub,
765 : : billterm_ns,
766 : : };
767 : :
768 : 61 : gnc_xml_register_backend(be_data);
769 : 61 : }
770 : :
771 : : GncBillTerm*
772 : 0 : gnc_billterm_xml_find_or_create (QofBook* book, GncGUID* guid)
773 : : {
774 : : GncBillTerm* term;
775 : : gchar guidstr[GUID_ENCODING_LENGTH + 1];
776 : :
777 : 0 : guid_to_string_buff (guid, guidstr);
778 : 0 : g_return_val_if_fail (book, NULL);
779 : 0 : g_return_val_if_fail (guid, NULL);
780 : 0 : term = gncBillTermLookup (book, guid);
781 : 0 : DEBUG ("looking for billterm %s, found %p", guidstr, term);
782 : 0 : if (!term)
783 : : {
784 : 0 : term = gncBillTermCreate (book);
785 : 0 : gncBillTermBeginEdit (term);
786 : 0 : gncBillTermSetGUID (term, guid);
787 : 0 : gncBillTermCommitEdit (term);
788 : 0 : DEBUG ("Created term: %p", term);
789 : : }
790 : : else
791 : 0 : gncBillTermDecRef (term);
792 : :
793 : 0 : return term;
794 : : }
|