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