GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-invoice-xml-v2.c
1 /********************************************************************\
2  * gnc-invoice-xml-v2.c -- invoice 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 "gncInvoiceP.h"
46 #include "gnc-invoice-xml-v2.h"
47 #include "gnc-owner-xml-v2.h"
48 #include "gnc-bill-term-xml-v2.h"
49 
50 #define _GNC_MOD_NAME GNC_ID_INVOICE
51 
52 static QofLogModule log_module = GNC_MOD_IO;
53 
54 const gchar *invoice_version_string = "2.0.0";
55 
56 /* ids */
57 #define gnc_invoice_string "gnc:GncInvoice"
58 #define invoice_guid_string "invoice:guid"
59 #define invoice_id_string "invoice:id"
60 #define invoice_owner_string "invoice:owner"
61 #define invoice_opened_string "invoice:opened"
62 #define invoice_posted_string "invoice:posted"
63 #define invoice_terms_string "invoice:terms"
64 #define invoice_billing_id_string "invoice:billing_id"
65 #define invoice_notes_string "invoice:notes"
66 #define invoice_active_string "invoice:active"
67 #define invoice_posttxn_string "invoice:posttxn"
68 #define invoice_postlot_string "invoice:postlot"
69 #define invoice_postacc_string "invoice:postacc"
70 #define invoice_currency_string "invoice:currency"
71 #define invoice_billto_string "invoice:billto"
72 #define invoice_tochargeamt_string "invoice:charge-amt"
73 #define invoice_slots_string "invoice:slots"
74 
75 /* EFFECTIVE FRIEND FUNCTION */
76 extern KvpFrame *qof_instance_get_slots (const QofInstance *);
77 
78 static void
79 maybe_add_string (xmlNodePtr ptr, const char *tag, const char *str)
80 {
81  if (str && strlen(str) > 0)
82  xmlAddChild (ptr, text_to_dom_tree (tag, str));
83 }
84 
85 static void
86 maybe_add_timespec (xmlNodePtr ptr, const char *tag, Timespec ts)
87 {
88  if (ts.tv_sec || ts.tv_nsec)
89  xmlAddChild (ptr, timespec_to_dom_tree (tag, &ts));
90 }
91 
92 static xmlNodePtr
93 invoice_dom_tree_create (GncInvoice *invoice)
94 {
95  xmlNodePtr ret;
96  KvpFrame *kf;
97  Timespec ts;
98  Transaction *txn;
99  GNCLot *lot;
100  Account *acc;
101  GncBillTerm *term;
102  GncOwner *billto;
103  gnc_numeric amt;
104 
105  ret = xmlNewNode(NULL, BAD_CAST gnc_invoice_string);
106  xmlSetProp(ret, BAD_CAST "version", BAD_CAST invoice_version_string);
107 
108  xmlAddChild(ret, guid_to_dom_tree(invoice_guid_string,
109  qof_instance_get_guid(QOF_INSTANCE(invoice))));
110 
111  xmlAddChild(ret, text_to_dom_tree(invoice_id_string,
112  gncInvoiceGetID (invoice)));
113 
114  xmlAddChild(ret, gnc_owner_to_dom_tree (invoice_owner_string,
115  gncInvoiceGetOwner (invoice)));
116 
117  ts = gncInvoiceGetDateOpened (invoice);
118  xmlAddChild(ret, timespec_to_dom_tree (invoice_opened_string, &ts));
119 
120  maybe_add_timespec (ret, invoice_posted_string,
121  gncInvoiceGetDatePosted (invoice));
122 
123  term = gncInvoiceGetTerms (invoice);
124  if (term)
125  xmlAddChild(ret, guid_to_dom_tree(invoice_terms_string,
126  qof_instance_get_guid (QOF_INSTANCE(term))));
127 
128  maybe_add_string (ret, invoice_billing_id_string,
129  gncInvoiceGetBillingID (invoice));
130  maybe_add_string (ret, invoice_notes_string, gncInvoiceGetNotes (invoice));
131 
132  xmlAddChild(ret, int_to_dom_tree(invoice_active_string,
133  gncInvoiceGetActive (invoice)));
134 
135  txn = gncInvoiceGetPostedTxn (invoice);
136  if (txn)
137  xmlAddChild (ret, guid_to_dom_tree (invoice_posttxn_string,
138  xaccTransGetGUID (txn)));
139 
140  lot = gncInvoiceGetPostedLot (invoice);
141  if (lot)
142  xmlAddChild (ret, guid_to_dom_tree (invoice_postlot_string,
143  gnc_lot_get_guid (lot)));
144 
145  acc = gncInvoiceGetPostedAcc (invoice);
146  if (acc)
147  xmlAddChild (ret, guid_to_dom_tree (invoice_postacc_string,
148  qof_instance_get_guid(QOF_INSTANCE(acc))));
149 
150  xmlAddChild
151  (ret,
152  commodity_ref_to_dom_tree(invoice_currency_string,
153  gncInvoiceGetCurrency (invoice)));
154 
155  billto = gncInvoiceGetBillTo (invoice);
156  if (billto && billto->owner.undefined != NULL)
157  xmlAddChild (ret, gnc_owner_to_dom_tree (invoice_billto_string, billto));
158 
159  amt = gncInvoiceGetToChargeAmount (invoice);
160  if (! gnc_numeric_zero_p (amt))
161  xmlAddChild (ret, gnc_numeric_to_dom_tree (invoice_tochargeamt_string, &amt));
162 
163  kf = qof_instance_get_slots (QOF_INSTANCE(invoice));
164  if (kf)
165  {
166  xmlNodePtr kvpnode = kvp_frame_to_dom_tree(invoice_slots_string, kf);
167  if (kvpnode)
168  {
169  xmlAddChild(ret, kvpnode);
170  }
171  }
172 
173  return ret;
174 }
175 
176 /***********************************************************************/
177 
179 {
180  GncInvoice *invoice;
181  QofBook *book;
182 };
183 
184 static inline gboolean
185 set_string(xmlNodePtr node, GncInvoice* invoice,
186  void (*func)(GncInvoice *invoice, const char *txt))
187 {
188  char* txt = dom_tree_to_text(node);
189  g_return_val_if_fail(txt, FALSE);
190 
191  func(invoice, txt);
192 
193  g_free(txt);
194  return TRUE;
195 }
196 
197 static inline gboolean
198 set_timespec(xmlNodePtr node, GncInvoice* invoice,
199  void (*func)(GncInvoice *invoice, Timespec ts))
200 {
201  Timespec ts = dom_tree_to_timespec(node);
202  if (!dom_tree_valid_timespec(&ts, node->name)) return FALSE;
203 
204  func(invoice, ts);
205  return TRUE;
206 }
207 
208 static gboolean
209 invoice_guid_handler (xmlNodePtr node, gpointer invoice_pdata)
210 {
211  struct invoice_pdata *pdata = invoice_pdata;
212  GncGUID *guid;
213  GncInvoice *invoice;
214 
215  guid = dom_tree_to_guid(node);
216  g_return_val_if_fail (guid, FALSE);
217  invoice = gncInvoiceLookup (pdata->book, guid);
218  if (invoice)
219  {
220  gncInvoiceDestroy (pdata->invoice);
221  pdata->invoice = invoice;
222  gncInvoiceBeginEdit (invoice);
223  }
224  else
225  {
226  gncInvoiceSetGUID(pdata->invoice, guid);
227  }
228 
229  g_free(guid);
230 
231  return TRUE;
232 }
233 
234 static gboolean
235 invoice_id_handler (xmlNodePtr node, gpointer invoice_pdata)
236 {
237  struct invoice_pdata *pdata = invoice_pdata;
238 
239  return set_string(node, pdata->invoice, gncInvoiceSetID);
240 }
241 
242 static gboolean
243 invoice_owner_handler (xmlNodePtr node, gpointer invoice_pdata)
244 {
245  struct invoice_pdata *pdata = invoice_pdata;
246  GncOwner owner;
247  gboolean ret;
248 
249  ret = gnc_dom_tree_to_owner (node, &owner, pdata->book);
250  if (ret)
251  gncInvoiceSetOwner (pdata->invoice, &owner);
252 
253  return ret;
254 }
255 
256 static gboolean
257 invoice_opened_handler (xmlNodePtr node, gpointer invoice_pdata)
258 {
259  struct invoice_pdata *pdata = invoice_pdata;
260 
261  return set_timespec (node, pdata->invoice, gncInvoiceSetDateOpened);
262 }
263 
264 static gboolean
265 invoice_posted_handler (xmlNodePtr node, gpointer invoice_pdata)
266 {
267  struct invoice_pdata *pdata = invoice_pdata;
268 
269  return set_timespec (node, pdata->invoice, gncInvoiceSetDatePosted);
270 }
271 
272 static gboolean
273 invoice_billing_id_handler (xmlNodePtr node, gpointer invoice_pdata)
274 {
275  struct invoice_pdata *pdata = invoice_pdata;
276 
277  return set_string(node, pdata->invoice, gncInvoiceSetBillingID);
278 }
279 
280 static gboolean
281 invoice_notes_handler (xmlNodePtr node, gpointer invoice_pdata)
282 {
283  struct invoice_pdata *pdata = invoice_pdata;
284 
285  return set_string(node, pdata->invoice, gncInvoiceSetNotes);
286 }
287 
288 static gboolean
289 invoice_active_handler (xmlNodePtr node, gpointer invoice_pdata)
290 {
291  struct invoice_pdata *pdata = invoice_pdata;
292  gint64 val;
293  gboolean ret;
294 
295  ret = dom_tree_to_integer(node, &val);
296  if (ret)
297  gncInvoiceSetActive(pdata->invoice, (gboolean)val);
298 
299  return ret;
300 }
301 
302 static gboolean
303 invoice_terms_handler (xmlNodePtr node, gpointer invoice_pdata)
304 {
305  struct invoice_pdata *pdata = invoice_pdata;
306  GncGUID *guid;
307  GncBillTerm *term;
308 
309  guid = dom_tree_to_guid(node);
310  g_return_val_if_fail (guid, FALSE);
311  term = gnc_billterm_xml_find_or_create(pdata->book, guid);
312  g_assert(term);
313  g_free (guid);
314  gncInvoiceSetTerms (pdata->invoice, term);
315 
316  return TRUE;
317 }
318 
319 static gboolean
320 invoice_posttxn_handler (xmlNodePtr node, gpointer invoice_pdata)
321 {
322  struct invoice_pdata *pdata = invoice_pdata;
323  GncGUID *guid;
324  Transaction *txn;
325 
326  guid = dom_tree_to_guid(node);
327  g_return_val_if_fail (guid, FALSE);
328  txn = xaccTransLookup (guid, pdata->book);
329  g_free (guid);
330  g_return_val_if_fail (txn, FALSE);
331 
332  gncInvoiceSetPostedTxn (pdata->invoice, txn);
333  return TRUE;
334 }
335 
336 static gboolean
337 invoice_postlot_handler (xmlNodePtr node, gpointer invoice_pdata)
338 {
339  struct invoice_pdata *pdata = invoice_pdata;
340  GncGUID *guid;
341  GNCLot *lot;
342 
343  guid = dom_tree_to_guid(node);
344  g_return_val_if_fail (guid, FALSE);
345  lot = gnc_lot_lookup (guid, pdata->book);
346  g_free (guid);
347  g_return_val_if_fail (lot, FALSE);
348 
349  gncInvoiceSetPostedLot (pdata->invoice, lot);
350  return TRUE;
351 }
352 
353 static gboolean
354 invoice_postacc_handler (xmlNodePtr node, gpointer invoice_pdata)
355 {
356  struct invoice_pdata *pdata = invoice_pdata;
357  GncGUID *guid;
358  Account *acc;
359 
360  guid = dom_tree_to_guid(node);
361  g_return_val_if_fail (guid, FALSE);
362  acc = xaccAccountLookup (guid, pdata->book);
363  g_free (guid);
364  g_return_val_if_fail (acc, FALSE);
365 
366  gncInvoiceSetPostedAcc (pdata->invoice, acc);
367  return TRUE;
368 }
369 
370 static gboolean
371 invoice_currency_handler (xmlNodePtr node, gpointer invoice_pdata)
372 {
373  struct invoice_pdata *pdata = invoice_pdata;
374  gnc_commodity *com;
375 
376  com = dom_tree_to_commodity_ref(node, pdata->book);
377  g_return_val_if_fail (com, FALSE);
378 
379  gncInvoiceSetCurrency (pdata->invoice, com);
380 
381  return TRUE;
382 }
383 
384 static gboolean
385 invoice_billto_handler (xmlNodePtr node, gpointer invoice_pdata)
386 {
387  struct invoice_pdata *pdata = invoice_pdata;
388  GncOwner owner;
389  gboolean ret;
390 
391  ret = gnc_dom_tree_to_owner (node, &owner, pdata->book);
392  if (ret)
393  gncInvoiceSetBillTo (pdata->invoice, &owner);
394 
395  return ret;
396 }
397 
398 static gboolean
399 invoice_tochargeamt_handler (xmlNodePtr node, gpointer invoice_pdata)
400 {
401  struct invoice_pdata *pdata = invoice_pdata;
402  gnc_numeric* num = dom_tree_to_gnc_numeric(node);
403  g_return_val_if_fail(num, FALSE);
404 
405  gncInvoiceSetToChargeAmount (pdata->invoice, *num);
406  g_free(num);
407  return TRUE;
408 }
409 
410 static gboolean
411 invoice_slots_handler (xmlNodePtr node, gpointer invoice_pdata)
412 {
413  struct invoice_pdata *pdata = invoice_pdata;
414 
415  return dom_tree_to_kvp_frame_given
416  (node, qof_instance_get_slots (QOF_INSTANCE (pdata->invoice)));
417 }
418 
419 static struct dom_tree_handler invoice_handlers_v2[] =
420 {
421  { invoice_guid_string, invoice_guid_handler, 1, 0 },
422  { invoice_id_string, invoice_id_handler, 1, 0 },
423  { invoice_owner_string, invoice_owner_handler, 1, 0 },
424  { invoice_opened_string, invoice_opened_handler, 1, 0 },
425  { invoice_posted_string, invoice_posted_handler, 0, 0 },
426  { invoice_billing_id_string, invoice_billing_id_handler, 0, 0 },
427  { invoice_notes_string, invoice_notes_handler, 0, 0 },
428  { invoice_active_string, invoice_active_handler, 1, 0 },
429  { invoice_terms_string, invoice_terms_handler, 0, 0 },
430  { invoice_posttxn_string, invoice_posttxn_handler, 0, 0 },
431  { invoice_postlot_string, invoice_postlot_handler, 0, 0 },
432  { invoice_postacc_string, invoice_postacc_handler, 0, 0 },
433  { invoice_currency_string, invoice_currency_handler, 0, 0 },
434  { "invoice:commodity", invoice_currency_handler, 0, 0 },
435  { invoice_billto_string, invoice_billto_handler, 0, 0 },
436  { invoice_tochargeamt_string, invoice_tochargeamt_handler, 0, 0},
437  { invoice_slots_string, invoice_slots_handler, 0, 0 },
438  { NULL, 0, 0, 0 }
439 };
440 
441 static GncInvoice*
442 dom_tree_to_invoice (xmlNodePtr node, QofBook *book)
443 {
444  struct invoice_pdata invoice_pdata;
445  gboolean successful;
446 
447  invoice_pdata.invoice = gncInvoiceCreate(book);
448  invoice_pdata.book = book;
449  gncInvoiceBeginEdit (invoice_pdata.invoice);
450 
451  successful = dom_tree_generic_parse (node, invoice_handlers_v2,
452  &invoice_pdata);
453 
454  if (successful)
455  gncInvoiceCommitEdit (invoice_pdata.invoice);
456  else
457  {
458  PERR ("failed to parse invoice tree");
459  gncInvoiceDestroy (invoice_pdata.invoice);
460  invoice_pdata.invoice = NULL;
461  }
462 
463  return invoice_pdata.invoice;
464 }
465 
466 static gboolean
467 gnc_invoice_end_handler(gpointer data_for_children,
468  GSList* data_from_children, GSList* sibling_data,
469  gpointer parent_data, gpointer global_data,
470  gpointer *result, const gchar *tag)
471 {
472  GncInvoice *invoice;
473  xmlNodePtr tree = (xmlNodePtr)data_for_children;
474  gxpf_data *gdata = (gxpf_data*)global_data;
475  QofBook *book = gdata->bookdata;
476 
477  if (parent_data)
478  {
479  return TRUE;
480  }
481 
482  /* OK. For some messed up reason this is getting called again with a
483  NULL tag. So we ignore those cases */
484  if (!tag)
485  {
486  return TRUE;
487  }
488 
489  g_return_val_if_fail(tree, FALSE);
490 
491  invoice = dom_tree_to_invoice(tree, book);
492  if (invoice != NULL)
493  {
494  gdata->cb(tag, gdata->parsedata, invoice);
495  }
496 
497  xmlFreeNode(tree);
498 
499  return invoice != NULL;
500 }
501 
502 static sixtp *
503 invoice_sixtp_parser_create(void)
504 {
505  return sixtp_dom_parser_new(gnc_invoice_end_handler, NULL, NULL);
506 }
507 
508 static gboolean
509 invoice_should_be_saved (GncInvoice *invoice)
510 {
511  const char *id;
512 
513  /* make sure this is a valid invoice before we save it -- should have an ID */
514  id = gncInvoiceGetID (invoice);
515  if (id == NULL || *id == '\0')
516  return FALSE;
517 
518  return TRUE;
519 }
520 
521 static void
522 do_count (QofInstance * invoice_p, gpointer count_p)
523 {
524  int *count = count_p;
525  if (invoice_should_be_saved ((GncInvoice *)invoice_p))
526  (*count)++;
527 }
528 
529 static int
530 invoice_get_count (QofBook *book)
531 {
532  int count = 0;
533  qof_object_foreach (_GNC_MOD_NAME, book, do_count, (gpointer) &count);
534  return count;
535 }
536 
537 static void
538 xml_add_invoice (QofInstance * invoice_p, gpointer out_p)
539 {
540  xmlNodePtr node;
541  GncInvoice *invoice = (GncInvoice *) invoice_p;
542  FILE *out = out_p;
543 
544  if (ferror(out))
545  return;
546  if (!invoice_should_be_saved (invoice))
547  return;
548 
549  node = invoice_dom_tree_create (invoice);
550  xmlElemDump(out, NULL, node);
551  xmlFreeNode (node);
552  if (ferror(out) || fprintf(out, "\n") < 0)
553  return;
554 }
555 
556 static gboolean
557 invoice_write (FILE *out, QofBook *book)
558 {
559  qof_object_foreach_sorted (_GNC_MOD_NAME, book, xml_add_invoice, (gpointer) out);
560  return ferror(out) == 0;
561 }
562 
563 static gboolean
564 invoice_ns(FILE *out)
565 {
566  g_return_val_if_fail(out, FALSE);
567  return gnc_xml2_write_namespace_decl(out, "invoice");
568 }
569 
570 void
571 gnc_invoice_xml_initialize (void)
572 {
573  static GncXmlDataType_t be_data =
574  {
575  GNC_FILE_BACKEND_VERS,
576  gnc_invoice_string,
577  invoice_sixtp_parser_create,
578  NULL, /* add_item */
579  invoice_get_count,
580  invoice_write,
581  NULL, /* scrub */
582  invoice_ns,
583  };
584 
585  qof_object_register_backend (_GNC_MOD_NAME,
587  &be_data);
588 }
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
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
gboolean gnc_numeric_zero_p(gnc_numeric a)
#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)
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
Definition: Transaction.c:1024
api for GnuCash version 2 XML-based file format
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
#define xaccTransGetGUID(X)
Definition: Transaction.h:755
gboolean gnc_xml2_write_namespace_decl(FILE *out, const char *name_space)
struct KvpFrameImpl KvpFrame
Definition: kvp_frame.h:76
const gchar * QofLogModule
Definition: qofid.h:89
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
Definition: Account.c:1827