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