GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-customer-xml-v2.c
1 /********************************************************************\
2  * gnc-customer-xml-v2.c -- customer 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 "gncCustomerP.h"
46 #include "gncTaxTableP.h"
47 #include "gnc-customer-xml-v2.h"
48 #include "gnc-address-xml-v2.h"
49 #include "gnc-bill-term-xml-v2.h"
50 
51 #include "xml-helpers.h"
52 
53 #define _GNC_MOD_NAME GNC_ID_CUSTOMER
54 
55 static QofLogModule log_module = GNC_MOD_IO;
56 
57 const gchar *customer_version_string = "2.0.0";
58 
59 /* ids */
60 #define gnc_customer_string "gnc:GncCustomer"
61 #define cust_name_string "cust:name"
62 #define cust_guid_string "cust:guid"
63 #define cust_id_string "cust:id"
64 #define cust_addr_string "cust:addr"
65 #define cust_shipaddr_string "cust:shipaddr"
66 #define cust_notes_string "cust:notes"
67 #define cust_terms_string "cust:terms"
68 #define cust_taxincluded_string "cust:taxincluded"
69 #define cust_active_string "cust:active"
70 #define cust_discount_string "cust:discount"
71 #define cust_credit_string "cust:credit"
72 #define cust_currency_string "cust:currency"
73 #define cust_taxtable_string "cust:taxtable"
74 #define cust_taxtableoverride_string "cust:use-tt"
75 #define cust_slots_string "cust:slots"
76 
77 static xmlNodePtr
78 customer_dom_tree_create (GncCustomer *cust)
79 {
80  xmlNodePtr ret, kvpnode;
81  gnc_numeric num;
82  GncBillTerm *term;
83  GncTaxTable *taxtable;
84 
85  ret = xmlNewNode(NULL, BAD_CAST gnc_customer_string);
86  xmlSetProp(ret, BAD_CAST "version", BAD_CAST customer_version_string);
87 
88  xmlAddChild(ret, guid_to_dom_tree(cust_guid_string,
89  qof_instance_get_guid(QOF_INSTANCE(cust))));
90 
91  xmlAddChild(ret, text_to_dom_tree(cust_name_string,
92  gncCustomerGetName (cust)));
93 
94  xmlAddChild(ret, text_to_dom_tree(cust_id_string,
95  gncCustomerGetID (cust)));
96 
97  xmlAddChild(ret, gnc_address_to_dom_tree(cust_addr_string,
98  gncCustomerGetAddr (cust)));
99 
100  xmlAddChild(ret, gnc_address_to_dom_tree(cust_shipaddr_string,
101  gncCustomerGetShipAddr (cust)));
102 
103  maybe_add_string (ret, cust_notes_string, gncCustomerGetNotes (cust));
104 
105  term = gncCustomerGetTerms (cust);
106  if (term)
107  xmlAddChild(ret, guid_to_dom_tree(cust_terms_string,
108  qof_instance_get_guid (QOF_INSTANCE(term))));
109 
110  xmlAddChild(ret, text_to_dom_tree(cust_taxincluded_string,
111  gncTaxIncludedTypeToString (
112  gncCustomerGetTaxIncluded (cust))));
113 
114  xmlAddChild(ret, int_to_dom_tree(cust_active_string,
115  gncCustomerGetActive (cust)));
116 
117  num = gncCustomerGetDiscount (cust);
118  xmlAddChild(ret, gnc_numeric_to_dom_tree(cust_discount_string, &num));
119 
120  num = gncCustomerGetCredit (cust);
121  xmlAddChild(ret, gnc_numeric_to_dom_tree(cust_credit_string, &num));
122 
123  xmlAddChild
124  (ret,
125  commodity_ref_to_dom_tree(cust_currency_string,
126  gncCustomerGetCurrency (cust)));
127 
128  xmlAddChild (ret, int_to_dom_tree (cust_taxtableoverride_string,
129  gncCustomerGetTaxTableOverride (cust)));
130  taxtable = gncCustomerGetTaxTable (cust);
131  if (taxtable)
132  xmlAddChild (ret, guid_to_dom_tree (cust_taxtable_string,
133  qof_instance_get_guid(QOF_INSTANCE(taxtable))));
134 
135  kvpnode = kvp_frame_to_dom_tree (cust_slots_string,
136  qof_instance_get_slots (QOF_INSTANCE(cust)));
137  if (kvpnode) xmlAddChild (ret, kvpnode);
138 
139  return ret;
140 }
141 
142 /***********************************************************************/
143 
145 {
146  GncCustomer *customer;
147  QofBook *book;
148 };
149 
150 static gboolean
151 set_string(xmlNodePtr node, GncCustomer* cust,
152  void (*func)(GncCustomer *cust, const char *txt))
153 {
154  char* txt = dom_tree_to_text(node);
155  g_return_val_if_fail(txt, FALSE);
156 
157  func(cust, txt);
158 
159  g_free(txt);
160 
161  return TRUE;
162 }
163 
164 static gboolean
165 set_boolean(xmlNodePtr node, GncCustomer* cust,
166  void (*func)(GncCustomer* cust, gboolean b))
167 {
168  gint64 val;
169  gboolean ret;
170 
171  ret = dom_tree_to_integer(node, &val);
172  if (ret)
173  func(cust, (gboolean)val);
174 
175  return ret;
176 }
177 
178 static gboolean
179 customer_name_handler (xmlNodePtr node, gpointer cust_pdata)
180 {
181  struct customer_pdata *pdata = cust_pdata;
182 
183  return set_string(node, pdata->customer, gncCustomerSetName);
184 }
185 
186 static gboolean
187 customer_guid_handler (xmlNodePtr node, gpointer cust_pdata)
188 {
189  struct customer_pdata *pdata = cust_pdata;
190  GncGUID *guid;
191  GncCustomer *cust;
192 
193  guid = dom_tree_to_guid(node);
194  g_return_val_if_fail(guid, FALSE);
195  cust = gncCustomerLookup (pdata->book, guid);
196  if (cust)
197  {
198  gncCustomerDestroy (pdata->customer);
199  pdata->customer = cust;
200  gncCustomerBeginEdit (cust);
201  }
202  else
203  {
204  gncCustomerSetGUID(pdata->customer, guid);
205  }
206 
207  g_free(guid);
208 
209  return TRUE;
210 }
211 
212 static gboolean
213 customer_id_handler (xmlNodePtr node, gpointer cust_pdata)
214 {
215  struct customer_pdata *pdata = cust_pdata;
216 
217  return set_string(node, pdata->customer, gncCustomerSetID);
218 }
219 
220 static gboolean
221 customer_notes_handler (xmlNodePtr node, gpointer cust_pdata)
222 {
223  struct customer_pdata *pdata = cust_pdata;
224 
225  return set_string(node, pdata->customer, gncCustomerSetNotes);
226 }
227 
228 static gboolean
229 customer_terms_handler (xmlNodePtr node, gpointer cust_pdata)
230 {
231  struct customer_pdata *pdata = cust_pdata;
232  GncGUID *guid;
233  GncBillTerm *term;
234 
235  guid = dom_tree_to_guid(node);
236  g_return_val_if_fail (guid, FALSE);
237  term = gnc_billterm_xml_find_or_create(pdata->book, guid);
238  g_assert(term);
239  g_free (guid);
240  gncCustomerSetTerms (pdata->customer, term);
241 
242  return TRUE;
243 }
244 
245 static gboolean
246 customer_addr_handler (xmlNodePtr node, gpointer cust_pdata)
247 {
248  struct customer_pdata *pdata = cust_pdata;
249 
250  return gnc_dom_tree_to_address (node, gncCustomerGetAddr(pdata->customer));
251 }
252 
253 static gboolean
254 customer_shipaddr_handler (xmlNodePtr node, gpointer cust_pdata)
255 {
256  struct customer_pdata *pdata = cust_pdata;
257 
258  return gnc_dom_tree_to_address (node,
259  gncCustomerGetShipAddr(pdata->customer));
260 }
261 
262 
263 static gboolean
264 customer_taxincluded_handler (xmlNodePtr node, gpointer cust_pdata)
265 {
266  struct customer_pdata *pdata = cust_pdata;
267  GncTaxIncluded type;
268  char *str;
269  gboolean ret;
270 
271  str = dom_tree_to_text (node);
272  g_return_val_if_fail (str, FALSE);
273 
274  ret = gncTaxIncludedStringToType (str, &type);
275  g_free (str);
276 
277  if (ret)
278  gncCustomerSetTaxIncluded(pdata->customer, type);
279 
280  return ret;
281 }
282 
283 static gboolean
284 customer_active_handler (xmlNodePtr node, gpointer cust_pdata)
285 {
286  struct customer_pdata *pdata = cust_pdata;
287  return set_boolean (node, pdata->customer, gncCustomerSetActive);
288 }
289 
290 static gboolean
291 customer_discount_handler (xmlNodePtr node, gpointer cust_pdata)
292 {
293  struct customer_pdata *pdata = cust_pdata;
294  gnc_numeric *val;
295 
296  val = dom_tree_to_gnc_numeric(node);
297  g_return_val_if_fail(val, FALSE);
298 
299  gncCustomerSetDiscount(pdata->customer, *val);
300  g_free (val);
301 
302  return TRUE;
303 }
304 
305 static gboolean
306 customer_credit_handler (xmlNodePtr node, gpointer cust_pdata)
307 {
308  struct customer_pdata *pdata = cust_pdata;
309  gnc_numeric *val;
310 
311  val = dom_tree_to_gnc_numeric(node);
312  g_return_val_if_fail(val, FALSE);
313 
314  gncCustomerSetCredit(pdata->customer, *val);
315  g_free (val);
316 
317  return TRUE;
318 }
319 
320 static gboolean
321 customer_currency_handler (xmlNodePtr node, gpointer customer_pdata)
322 {
323  struct customer_pdata *pdata = customer_pdata;
324  gnc_commodity *com;
325 
326  com = dom_tree_to_commodity_ref(node, pdata->book);
327  g_return_val_if_fail (com, FALSE);
328 
329  gncCustomerSetCurrency (pdata->customer, com);
330 
331  return TRUE;
332 }
333 
334 static gboolean
335 customer_taxtable_handler (xmlNodePtr node, gpointer cust_pdata)
336 {
337  struct customer_pdata *pdata = cust_pdata;
338  GncGUID *guid;
339  GncTaxTable *taxtable;
340 
341  guid = dom_tree_to_guid (node);
342  g_return_val_if_fail (guid, FALSE);
343  taxtable = gncTaxTableLookup (pdata->book, guid);
344  if (!taxtable)
345  {
346  taxtable = gncTaxTableCreate (pdata->book);
347  gncTaxTableBeginEdit (taxtable);
348  gncTaxTableSetGUID (taxtable, guid);
349  gncTaxTableCommitEdit (taxtable);
350  }
351  else
352  gncTaxTableDecRef (taxtable);
353 
354  gncCustomerSetTaxTable (pdata->customer, taxtable);
355  g_free(guid);
356  return TRUE;
357 }
358 
359 static gboolean
360 customer_taxtableoverride_handler (xmlNodePtr node, gpointer cust_pdata)
361 {
362  struct customer_pdata *pdata = cust_pdata;
363  return set_boolean (node, pdata->customer, gncCustomerSetTaxTableOverride);
364 }
365 
366 static gboolean
367 customer_slots_handler (xmlNodePtr node, gpointer cust_pdata)
368 {
369  struct customer_pdata *pdata = cust_pdata;
370  return dom_tree_to_kvp_frame_given (node,
371  qof_instance_get_slots (QOF_INSTANCE(pdata->customer)));
372 }
373 
374 static struct dom_tree_handler customer_handlers_v2[] =
375 {
376  { cust_name_string, customer_name_handler, 1, 0 },
377  { cust_guid_string, customer_guid_handler, 1, 0 },
378  { cust_id_string, customer_id_handler, 1, 0 },
379  { cust_addr_string, customer_addr_handler, 1, 0 },
380  { cust_shipaddr_string, customer_shipaddr_handler, 1, 0 },
381  { cust_notes_string, customer_notes_handler, 0, 0 },
382  { cust_terms_string, customer_terms_handler, 0, 0 },
383  { cust_taxincluded_string, customer_taxincluded_handler, 1, 0 },
384  { cust_active_string, customer_active_handler, 1, 0 },
385  { cust_discount_string, customer_discount_handler, 1, 0 },
386  { cust_credit_string, customer_credit_handler, 1, 0 },
387  { cust_currency_string, customer_currency_handler, 0, 0 }, /* XXX */
388  { "cust:commodity", customer_currency_handler, 0, 0 }, /* XXX */
389  { cust_taxtable_string, customer_taxtable_handler, 0, 0 },
390  { cust_taxtableoverride_string, customer_taxtableoverride_handler, 0, 0 },
391  { cust_slots_string, customer_slots_handler, 0, 0 },
392  { NULL, 0, 0, 0 }
393 };
394 
395 static GncCustomer*
396 dom_tree_to_customer (xmlNodePtr node, QofBook *book)
397 {
398  struct customer_pdata cust_pdata;
399  gboolean successful;
400 
401  cust_pdata.customer = gncCustomerCreate(book);
402  cust_pdata.book = book;
403  gncCustomerBeginEdit (cust_pdata.customer);
404 
405  successful = dom_tree_generic_parse (node, customer_handlers_v2,
406  &cust_pdata);
407 
408  if (successful)
409  gncCustomerCommitEdit (cust_pdata.customer);
410  else
411  {
412  PERR ("failed to parse customer tree");
413  gncCustomerDestroy (cust_pdata.customer);
414  cust_pdata.customer = NULL;
415  }
416 
417  return cust_pdata.customer;
418 }
419 
420 static gboolean
421 gnc_customer_end_handler(gpointer data_for_children,
422  GSList* data_from_children, GSList* sibling_data,
423  gpointer parent_data, gpointer global_data,
424  gpointer *result, const gchar *tag)
425 {
426  GncCustomer *cust;
427  xmlNodePtr tree = (xmlNodePtr)data_for_children;
428  gxpf_data *gdata = (gxpf_data*)global_data;
429  QofBook *book = gdata->bookdata;
430 
431 
432  if (parent_data)
433  {
434  return TRUE;
435  }
436 
437  /* OK. For some messed up reason this is getting called again with a
438  NULL tag. So we ignore those cases */
439  if (!tag)
440  {
441  return TRUE;
442  }
443 
444  g_return_val_if_fail(tree, FALSE);
445 
446  cust = dom_tree_to_customer(tree, book);
447  if (cust != NULL)
448  {
449  gdata->cb(tag, gdata->parsedata, cust);
450  }
451 
452  xmlFreeNode(tree);
453 
454  return cust != NULL;
455 }
456 
457 static sixtp *
458 customer_sixtp_parser_create(void)
459 {
460  return sixtp_dom_parser_new(gnc_customer_end_handler, NULL, NULL);
461 }
462 
463 static gboolean
464 customer_should_be_saved (GncCustomer *customer)
465 {
466  const char *id;
467 
468  /* make sure this is a valid customer before we save it -- should have an ID */
469  id = gncCustomerGetID (customer);
470  if (id == NULL || *id == '\0')
471  return FALSE;
472 
473  return TRUE;
474 }
475 
476 static void
477 do_count (QofInstance * cust_p, gpointer count_p)
478 {
479  int *count = count_p;
480  if (customer_should_be_saved ((GncCustomer *)cust_p))
481  (*count)++;
482 }
483 
484 static int
485 customer_get_count (QofBook *book)
486 {
487  int count = 0;
488  qof_object_foreach (_GNC_MOD_NAME, book, do_count, (gpointer) &count);
489  return count;
490 }
491 
492 static void
493 xml_add_customer (QofInstance * cust_p, gpointer out_p)
494 {
495  xmlNodePtr node;
496  GncCustomer *cust = (GncCustomer *) cust_p;
497  FILE *out = out_p;
498 
499  if (ferror(out))
500  return;
501  if (!customer_should_be_saved (cust))
502  return;
503 
504  node = customer_dom_tree_create (cust);
505  xmlElemDump(out, NULL, node);
506  xmlFreeNode (node);
507  if (ferror(out) || fprintf(out, "\n") < 0)
508  return;
509 }
510 
511 static gboolean
512 customer_write (FILE *out, QofBook *book)
513 {
514  qof_object_foreach_sorted (_GNC_MOD_NAME, book, xml_add_customer, (gpointer) out);
515  return ferror(out) == 0;
516 }
517 
518 static gboolean
519 customer_ns(FILE *out)
520 {
521  g_return_val_if_fail(out, FALSE);
522  return gnc_xml2_write_namespace_decl(out, "cust");
523 }
524 
525 void
526 gnc_customer_xml_initialize (void)
527 {
528  static GncXmlDataType_t be_data =
529  {
530  GNC_FILE_BACKEND_VERS,
531  gnc_customer_string,
532  customer_sixtp_parser_create,
533  NULL, /* add_item */
534  customer_get_count,
535  customer_write,
536  NULL, /* scrub */
537  customer_ns,
538  };
539 
540  qof_object_register_backend (_GNC_MOD_NAME,
542  &be_data);
543 }
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
GncTaxIncluded
Definition: gncTaxTable.h:100
#define PERR(format, args...)
Definition: qoflog.h:237
Definition: guid.h:65
void qof_object_foreach_sorted(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
api for GnuCash version 2 XML-based file format
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
gboolean gnc_xml2_write_namespace_decl(FILE *out, const char *name_space)
const gchar * QofLogModule
Definition: qofid.h:89