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 : :
149 : : static gboolean
150 : 2 : set_boolean (xmlNodePtr node, GncCustomer* cust,
151 : : void (*func) (GncCustomer* cust, gboolean b))
152 : : {
153 : : gint64 val;
154 : : gboolean ret;
155 : :
156 : 2 : ret = dom_tree_to_integer (node, &val);
157 : 2 : if (ret)
158 : 2 : func (cust, (gboolean)val);
159 : :
160 : 2 : return ret;
161 : : }
162 : :
163 : : static gboolean
164 : 1 : customer_name_handler (xmlNodePtr node, gpointer cust_pdata)
165 : : {
166 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
167 : :
168 : 1 : return apply_xmlnode_text (gncCustomerSetName, pdata->customer, node);
169 : : }
170 : :
171 : : static gboolean
172 : 1 : customer_guid_handler (xmlNodePtr node, gpointer cust_pdata)
173 : : {
174 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
175 : : GncCustomer* cust;
176 : :
177 : 1 : auto guid = dom_tree_to_guid (node);
178 : 1 : g_return_val_if_fail (guid, FALSE);
179 : 1 : cust = gncCustomerLookup (pdata->book, &*guid);
180 : 1 : if (cust)
181 : : {
182 : 0 : gncCustomerDestroy (pdata->customer);
183 : 0 : pdata->customer = cust;
184 : 0 : gncCustomerBeginEdit (cust);
185 : : }
186 : : else
187 : : {
188 : 1 : gncCustomerSetGUID (pdata->customer, &*guid);
189 : : }
190 : :
191 : 1 : return TRUE;
192 : : }
193 : :
194 : : static gboolean
195 : 1 : customer_id_handler (xmlNodePtr node, gpointer cust_pdata)
196 : : {
197 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
198 : :
199 : 1 : return apply_xmlnode_text (gncCustomerSetID, pdata->customer, node);
200 : : }
201 : :
202 : : static gboolean
203 : 1 : customer_notes_handler (xmlNodePtr node, gpointer cust_pdata)
204 : : {
205 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
206 : :
207 : 1 : return apply_xmlnode_text (gncCustomerSetNotes, pdata->customer, node);
208 : : }
209 : :
210 : : static gboolean
211 : 0 : customer_terms_handler (xmlNodePtr node, gpointer cust_pdata)
212 : : {
213 : 0 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
214 : : GncBillTerm* term;
215 : :
216 : 0 : auto guid = dom_tree_to_guid (node);
217 : 0 : g_return_val_if_fail (guid, FALSE);
218 : 0 : term = gnc_billterm_xml_find_or_create (pdata->book, &*guid);
219 : 0 : g_assert (term);
220 : 0 : gncCustomerSetTerms (pdata->customer, term);
221 : :
222 : 0 : return TRUE;
223 : : }
224 : :
225 : : static gboolean
226 : 1 : customer_addr_handler (xmlNodePtr node, gpointer cust_pdata)
227 : : {
228 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
229 : :
230 : 1 : return gnc_dom_tree_to_address (node, gncCustomerGetAddr (pdata->customer));
231 : : }
232 : :
233 : : static gboolean
234 : 1 : customer_shipaddr_handler (xmlNodePtr node, gpointer cust_pdata)
235 : : {
236 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
237 : :
238 : 1 : return gnc_dom_tree_to_address (node,
239 : 2 : gncCustomerGetShipAddr (pdata->customer));
240 : : }
241 : :
242 : :
243 : : static gboolean
244 : 1 : customer_taxincluded_handler (xmlNodePtr node, gpointer cust_pdata)
245 : : {
246 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
247 : 1 : auto set_tax_included = [](GncCustomer* cust, const char *str)
248 : : {
249 : : GncTaxIncluded type;
250 : 1 : if (gncTaxIncludedStringToType (str, &type))
251 : 1 : gncCustomerSetTaxIncluded (cust, type);
252 : 1 : };
253 : 2 : return apply_xmlnode_text (set_tax_included, pdata->customer, node);
254 : : }
255 : :
256 : : static gboolean
257 : 1 : customer_active_handler (xmlNodePtr node, gpointer cust_pdata)
258 : : {
259 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
260 : 1 : return set_boolean (node, pdata->customer, gncCustomerSetActive);
261 : : }
262 : :
263 : : static gboolean
264 : 1 : customer_discount_handler (xmlNodePtr node, gpointer cust_pdata)
265 : : {
266 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
267 : :
268 : 1 : gncCustomerSetDiscount (pdata->customer, dom_tree_to_gnc_numeric (node));
269 : 1 : return TRUE;
270 : : }
271 : :
272 : : static gboolean
273 : 1 : customer_credit_handler (xmlNodePtr node, gpointer cust_pdata)
274 : : {
275 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
276 : :
277 : 1 : gncCustomerSetCredit (pdata->customer, dom_tree_to_gnc_numeric (node));
278 : 1 : return TRUE;
279 : : }
280 : :
281 : : static gboolean
282 : 1 : customer_currency_handler (xmlNodePtr node, gpointer customer_pdata)
283 : : {
284 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (customer_pdata);
285 : : gnc_commodity* com;
286 : :
287 : 1 : com = dom_tree_to_commodity_ref (node, pdata->book);
288 : 1 : g_return_val_if_fail (com, FALSE);
289 : :
290 : 1 : gncCustomerSetCurrency (pdata->customer, com);
291 : :
292 : 1 : return TRUE;
293 : : }
294 : :
295 : : static gboolean
296 : 0 : customer_taxtable_handler (xmlNodePtr node, gpointer cust_pdata)
297 : : {
298 : 0 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
299 : : GncTaxTable* taxtable;
300 : :
301 : 0 : auto guid = dom_tree_to_guid (node);
302 : 0 : g_return_val_if_fail (guid, FALSE);
303 : 0 : taxtable = gncTaxTableLookup (pdata->book, &*guid);
304 : 0 : if (!taxtable)
305 : : {
306 : 0 : taxtable = gncTaxTableCreate (pdata->book);
307 : 0 : gncTaxTableBeginEdit (taxtable);
308 : 0 : gncTaxTableSetGUID (taxtable, &*guid);
309 : 0 : gncTaxTableCommitEdit (taxtable);
310 : : }
311 : : else
312 : 0 : gncTaxTableDecRef (taxtable);
313 : :
314 : 0 : gncCustomerSetTaxTable (pdata->customer, taxtable);
315 : 0 : return TRUE;
316 : : }
317 : :
318 : : static gboolean
319 : 1 : customer_taxtableoverride_handler (xmlNodePtr node, gpointer cust_pdata)
320 : : {
321 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
322 : 1 : return set_boolean (node, pdata->customer, gncCustomerSetTaxTableOverride);
323 : : }
324 : :
325 : : static gboolean
326 : 1 : customer_slots_handler (xmlNodePtr node, gpointer cust_pdata)
327 : : {
328 : 1 : struct customer_pdata* pdata = static_cast<decltype (pdata)> (cust_pdata);
329 : 1 : return dom_tree_create_instance_slots (node, QOF_INSTANCE (pdata->customer));
330 : : }
331 : :
332 : : static struct dom_tree_handler customer_handlers_v2[] =
333 : : {
334 : : { cust_name_string, customer_name_handler, 1, 0 },
335 : : { cust_guid_string, customer_guid_handler, 1, 0 },
336 : : { cust_id_string, customer_id_handler, 1, 0 },
337 : : { cust_addr_string, customer_addr_handler, 1, 0 },
338 : : { cust_shipaddr_string, customer_shipaddr_handler, 1, 0 },
339 : : { cust_notes_string, customer_notes_handler, 0, 0 },
340 : : { cust_terms_string, customer_terms_handler, 0, 0 },
341 : : { cust_taxincluded_string, customer_taxincluded_handler, 1, 0 },
342 : : { cust_active_string, customer_active_handler, 1, 0 },
343 : : { cust_discount_string, customer_discount_handler, 1, 0 },
344 : : { cust_credit_string, customer_credit_handler, 1, 0 },
345 : : { cust_currency_string, customer_currency_handler, 0, 0 }, /* XXX */
346 : : { "cust:commodity", customer_currency_handler, 0, 0 }, /* XXX */
347 : : { cust_taxtable_string, customer_taxtable_handler, 0, 0 },
348 : : { cust_taxtableoverride_string, customer_taxtableoverride_handler, 0, 0 },
349 : : { cust_slots_string, customer_slots_handler, 0, 0 },
350 : : { NULL, 0, 0, 0 }
351 : : };
352 : :
353 : : static GncCustomer*
354 : 1 : dom_tree_to_customer (xmlNodePtr node, QofBook* book)
355 : : {
356 : : struct customer_pdata cust_pdata;
357 : : gboolean successful;
358 : :
359 : 1 : cust_pdata.customer = gncCustomerCreate (book);
360 : 1 : cust_pdata.book = book;
361 : 1 : gncCustomerBeginEdit (cust_pdata.customer);
362 : :
363 : 1 : successful = dom_tree_generic_parse (node, customer_handlers_v2,
364 : : &cust_pdata);
365 : :
366 : 1 : if (successful)
367 : 1 : gncCustomerCommitEdit (cust_pdata.customer);
368 : : else
369 : : {
370 : 0 : PERR ("failed to parse customer tree");
371 : 0 : gncCustomerDestroy (cust_pdata.customer);
372 : 0 : cust_pdata.customer = NULL;
373 : : }
374 : :
375 : 1 : return cust_pdata.customer;
376 : : }
377 : :
378 : : static gboolean
379 : 33 : gnc_customer_end_handler (gpointer data_for_children,
380 : : GSList* data_from_children, GSList* sibling_data,
381 : : gpointer parent_data, gpointer global_data,
382 : : gpointer* result, const gchar* tag)
383 : : {
384 : : GncCustomer* cust;
385 : 33 : xmlNodePtr tree = (xmlNodePtr)data_for_children;
386 : 33 : gxpf_data* gdata = (gxpf_data*)global_data;
387 : 33 : QofBook* book = static_cast<decltype (book)> (gdata->bookdata);
388 : :
389 : :
390 : 33 : if (parent_data)
391 : : {
392 : 32 : return TRUE;
393 : : }
394 : :
395 : : /* OK. For some messed up reason this is getting called again with a
396 : : NULL tag. So we ignore those cases */
397 : 1 : if (!tag)
398 : : {
399 : 0 : return TRUE;
400 : : }
401 : :
402 : 1 : g_return_val_if_fail (tree, FALSE);
403 : :
404 : 1 : cust = dom_tree_to_customer (tree, book);
405 : 1 : if (cust != NULL)
406 : : {
407 : 1 : gdata->cb (tag, gdata->parsedata, cust);
408 : : }
409 : :
410 : 1 : xmlFreeNode (tree);
411 : :
412 : 1 : return cust != NULL;
413 : : }
414 : :
415 : : static sixtp*
416 : 22 : customer_sixtp_parser_create (void)
417 : : {
418 : 22 : return sixtp_dom_parser_new (gnc_customer_end_handler, NULL, NULL);
419 : : }
420 : :
421 : : static gboolean
422 : 0 : customer_should_be_saved (GncCustomer* customer)
423 : : {
424 : : const char* id;
425 : :
426 : : /* make sure this is a valid customer before we save it -- should have an ID */
427 : 0 : id = gncCustomerGetID (customer);
428 : 0 : if (id == NULL || *id == '\0')
429 : 0 : return FALSE;
430 : :
431 : 0 : return TRUE;
432 : : }
433 : :
434 : : static void
435 : 0 : do_count (QofInstance* cust_p, gpointer count_p)
436 : : {
437 : 0 : int* count = static_cast<decltype (count)> (count_p);
438 : 0 : if (customer_should_be_saved ((GncCustomer*)cust_p))
439 : 0 : (*count)++;
440 : 0 : }
441 : :
442 : : static int
443 : 4 : customer_get_count (QofBook* book)
444 : : {
445 : 4 : int count = 0;
446 : 4 : qof_object_foreach (_GNC_MOD_NAME, book, do_count, (gpointer) &count);
447 : 4 : return count;
448 : : }
449 : :
450 : : static void
451 : 0 : xml_add_customer (QofInstance* cust_p, gpointer out_p)
452 : : {
453 : : xmlNodePtr node;
454 : 0 : GncCustomer* cust = (GncCustomer*) cust_p;
455 : 0 : FILE* out = static_cast<decltype (out)> (out_p);
456 : :
457 : 0 : if (ferror (out))
458 : 0 : return;
459 : 0 : if (!customer_should_be_saved (cust))
460 : 0 : return;
461 : :
462 : 0 : node = customer_dom_tree_create (cust);
463 : 0 : xmlElemDump (out, NULL, node);
464 : 0 : xmlFreeNode (node);
465 : 0 : if (ferror (out) || fprintf (out, "\n") < 0)
466 : 0 : return;
467 : : }
468 : :
469 : : static gboolean
470 : 4 : customer_write (FILE* out, QofBook* book)
471 : : {
472 : 4 : qof_object_foreach_sorted (_GNC_MOD_NAME, book, xml_add_customer,
473 : : (gpointer) out);
474 : 4 : return ferror (out) == 0;
475 : : }
476 : :
477 : : static gboolean
478 : 4 : customer_ns (FILE* out)
479 : : {
480 : 4 : g_return_val_if_fail (out, FALSE);
481 : 4 : return gnc_xml2_write_namespace_decl (out, "cust");
482 : : }
483 : :
484 : : void
485 : 15 : gnc_customer_xml_initialize (void)
486 : : {
487 : : static GncXmlDataType_t be_data =
488 : : {
489 : : GNC_FILE_BACKEND_VERS,
490 : : gnc_customer_string,
491 : : customer_sixtp_parser_create,
492 : : NULL, /* add_item */
493 : : customer_get_count,
494 : : customer_write,
495 : : NULL, /* scrub */
496 : : customer_ns,
497 : : };
498 : :
499 : 15 : gnc_xml_register_backend (be_data);
500 : 15 : }
|