1
/********************************************************************\
2
* gnc-entry-xml-v2.c -- entry xml i/o implementation *
4
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU> *
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. *
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. *
16
* You should have received a copy of the GNU General Public License*
17
* along with this program; if not, contact: *
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 *
23
\********************************************************************/
31
#include "gnc-xml-helper.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"
41
#include "io-gncxml-gen.h"
42
#include "io-gncxml-v2.h"
44
#include "gncEntryP.h"
45
#include "gncOrderP.h"
46
#include "gncInvoiceP.h"
47
#include "gncTaxTableP.h"
48
#include "gnc-entry-xml-v2.h"
49
#include "gnc-owner-xml-v2.h"
51
#define _GNC_MOD_NAME GNC_ID_ENTRY
53
static QofLogModule log_module = GNC_MOD_IO;
55
const gchar *entry_version_string = "2.0.0";
58
#define gnc_entry_string "gnc:GncEntry"
59
#define entry_guid_string "entry:guid"
60
#define entry_date_string "entry:date"
61
#define entry_dateentered_string "entry:entered"
62
#define entry_description_string "entry:description"
63
#define entry_action_string "entry:action"
64
#define entry_notes_string "entry:notes"
65
#define entry_qty_string "entry:qty"
68
#define entry_invacct_string "entry:i-acct"
69
#define entry_iprice_string "entry:i-price"
70
#define entry_idiscount_string "entry:i-discount"
71
#define entry_idisctype_string "entry:i-disc-type"
72
#define entry_idischow_string "entry:i-disc-how"
73
#define entry_itaxable_string "entry:i-taxable"
74
#define entry_itaxincluded_string "entry:i-taxincluded"
75
#define entry_itaxtable_string "entry:i-taxtable"
78
#define entry_billacct_string "entry:b-acct"
79
#define entry_bprice_string "entry:b-price"
80
#define entry_btaxable_string "entry:b-taxable"
81
#define entry_btaxincluded_string "entry:b-taxincluded"
82
#define entry_btaxtable_string "entry:b-taxtable"
83
#define entry_billable_string "entry:billable"
84
#define entry_billto_string "entry:billto"
87
#define entry_billpayment_string "entry:b-pay"
90
#define entry_order_string "entry:order"
91
#define entry_invoice_string "entry:invoice"
92
#define entry_bill_string "entry:bill"
93
#define entry_slots_string "entry:slots"
96
maybe_add_string (xmlNodePtr ptr, const char *tag, const char *str)
98
if (str && strlen(str) > 0)
99
xmlAddChild (ptr, text_to_dom_tree (tag, str));
103
maybe_add_numeric (xmlNodePtr ptr, const char *tag, gnc_numeric num)
105
if (!gnc_numeric_zero_p (num))
106
xmlAddChild (ptr, gnc_numeric_to_dom_tree (tag, &num));
110
entry_dom_tree_create (GncEntry *entry)
115
GncTaxTable *taxtable;
119
ret = xmlNewNode(NULL, BAD_CAST gnc_entry_string);
120
xmlSetProp(ret, BAD_CAST "version", BAD_CAST entry_version_string);
122
xmlAddChild(ret, guid_to_dom_tree(entry_guid_string,
123
qof_instance_get_guid(QOF_INSTANCE(entry))));
125
ts = gncEntryGetDate (entry);
126
xmlAddChild(ret, timespec_to_dom_tree (entry_date_string, &ts));
128
ts = gncEntryGetDateEntered (entry);
129
xmlAddChild(ret, timespec_to_dom_tree (entry_dateentered_string, &ts));
131
maybe_add_string (ret, entry_description_string,
132
gncEntryGetDescription (entry));
133
maybe_add_string (ret, entry_action_string, gncEntryGetAction (entry));
134
maybe_add_string (ret, entry_notes_string, gncEntryGetNotes (entry));
136
maybe_add_numeric (ret, entry_qty_string, gncEntryGetQuantity (entry));
140
acc = gncEntryGetInvAccount (entry);
142
xmlAddChild (ret, guid_to_dom_tree (entry_invacct_string,
143
qof_instance_get_guid(QOF_INSTANCE(acc))));
145
maybe_add_numeric (ret, entry_iprice_string, gncEntryGetInvPrice (entry));
147
maybe_add_numeric (ret, entry_idiscount_string, gncEntryGetInvDiscount (entry));
149
invoice = gncEntryGetInvoice (entry);
151
xmlAddChild (ret, guid_to_dom_tree (entry_invoice_string,
152
qof_instance_get_guid(QOF_INSTANCE(invoice))));
154
xmlAddChild(ret, text_to_dom_tree(entry_idisctype_string,
155
gncAmountTypeToString (
156
gncEntryGetInvDiscountType (entry))));
157
xmlAddChild(ret, text_to_dom_tree(entry_idischow_string,
158
gncEntryDiscountHowToString (
159
gncEntryGetInvDiscountHow (entry))));
161
xmlAddChild(ret, int_to_dom_tree(entry_itaxable_string,
162
gncEntryGetInvTaxable (entry)));
163
xmlAddChild(ret, int_to_dom_tree(entry_itaxincluded_string,
164
gncEntryGetInvTaxIncluded (entry)));
167
taxtable = gncEntryGetInvTaxTable (entry);
169
xmlAddChild (ret, guid_to_dom_tree (entry_itaxtable_string,
170
qof_instance_get_guid (QOF_INSTANCE(taxtable))));
174
acc = gncEntryGetBillAccount (entry);
176
xmlAddChild (ret, guid_to_dom_tree (entry_billacct_string,
177
qof_instance_get_guid (QOF_INSTANCE(acc))));
179
maybe_add_numeric (ret, entry_bprice_string, gncEntryGetBillPrice (entry));
181
invoice = gncEntryGetBill (entry);
184
xmlAddChild (ret, guid_to_dom_tree (entry_bill_string,
185
qof_instance_get_guid(QOF_INSTANCE(invoice))));
186
xmlAddChild(ret, int_to_dom_tree(entry_billable_string,
187
gncEntryGetBillable (entry)));
188
owner = gncEntryGetBillTo (entry);
189
if (owner && owner->owner.undefined != NULL)
190
xmlAddChild (ret, gnc_owner_to_dom_tree (entry_billto_string, owner));
192
xmlAddChild(ret, int_to_dom_tree(entry_btaxable_string,
193
gncEntryGetBillTaxable (entry)));
194
xmlAddChild(ret, int_to_dom_tree(entry_btaxincluded_string,
195
gncEntryGetBillTaxIncluded (entry)));
196
maybe_add_string (ret, entry_billpayment_string,
197
gncEntryPaymentTypeToString (gncEntryGetBillPayment (entry)));
200
taxtable = gncEntryGetBillTaxTable (entry);
202
xmlAddChild (ret, guid_to_dom_tree (entry_btaxtable_string,
203
qof_instance_get_guid (QOF_INSTANCE(taxtable))));
207
order = gncEntryGetOrder (entry);
209
xmlAddChild (ret, guid_to_dom_tree (entry_order_string,
210
qof_instance_get_guid(QOF_INSTANCE (order))));
215
/***********************************************************************/
224
static inline gboolean
225
set_string(xmlNodePtr node, GncEntry* entry,
226
void (*func)(GncEntry *entry, const char *txt))
228
char* txt = dom_tree_to_text(node);
229
g_return_val_if_fail(txt, FALSE);
236
static inline gboolean
237
set_timespec(xmlNodePtr node, GncEntry* entry,
238
void (*func)(GncEntry *entry, Timespec ts))
240
Timespec ts = dom_tree_to_timespec (node);
241
if (!dom_tree_valid_timespec(&ts, node->name)) return FALSE;
247
static inline gboolean
248
set_numeric(xmlNodePtr node, GncEntry* entry,
249
void (*func)(GncEntry *entry, gnc_numeric num))
251
gnc_numeric* num = dom_tree_to_gnc_numeric(node);
252
g_return_val_if_fail(num, FALSE);
259
static inline gboolean
260
set_boolean(xmlNodePtr node, GncEntry* entry,
261
void (*func)(GncEntry *entry, gboolean val))
265
if (!dom_tree_to_integer(node, &val))
267
func (entry, (gboolean)val);
271
static inline gboolean
272
set_account(xmlNodePtr node, struct entry_pdata *pdata,
273
void (*func)(GncEntry *entry, Account *acc))
278
guid = dom_tree_to_guid (node);
279
g_return_val_if_fail (guid, FALSE);
280
acc = xaccAccountLookup (guid, pdata->book);
282
g_return_val_if_fail (acc, FALSE);
285
func (pdata->entry, acc);
291
static inline gboolean
292
set_taxtable (xmlNodePtr node, struct entry_pdata *pdata,
293
void (*func)(GncEntry *entry, GncTaxTable *taxtable))
296
GncTaxTable *taxtable;
298
guid = dom_tree_to_guid (node);
299
g_return_val_if_fail (guid, FALSE);
300
taxtable = gncTaxTableLookup (pdata->book, guid);
302
taxtable = gncTaxTableCreate (pdata->book);
303
gncTaxTableBeginEdit (taxtable);
304
gncTaxTableSetGUID (taxtable, guid);
305
gncTaxTableCommitEdit (taxtable);
307
gncTaxTableDecRef (taxtable);
309
func (pdata->entry, taxtable);
315
entry_guid_handler (xmlNodePtr node, gpointer entry_pdata)
317
struct entry_pdata *pdata = entry_pdata;
321
guid = dom_tree_to_guid(node);
322
g_return_val_if_fail (guid, FALSE);
323
entry = gncEntryLookup (pdata->book, guid);
325
gncEntryDestroy (pdata->entry);
326
pdata->entry = entry;
327
gncEntryBeginEdit (entry);
329
gncEntrySetGUID(pdata->entry, guid);
338
entry_date_handler (xmlNodePtr node, gpointer entry_pdata)
340
struct entry_pdata *pdata = entry_pdata;
342
return set_timespec(node, pdata->entry, gncEntrySetDate);
346
entry_dateentered_handler (xmlNodePtr node, gpointer entry_pdata)
348
struct entry_pdata *pdata = entry_pdata;
350
return set_timespec(node, pdata->entry, gncEntrySetDateEntered);
354
entry_description_handler (xmlNodePtr node, gpointer entry_pdata)
356
struct entry_pdata *pdata = entry_pdata;
358
return set_string(node, pdata->entry, gncEntrySetDescription);
362
entry_action_handler (xmlNodePtr node, gpointer entry_pdata)
364
struct entry_pdata *pdata = entry_pdata;
366
return set_string(node, pdata->entry, gncEntrySetAction);
370
entry_notes_handler (xmlNodePtr node, gpointer entry_pdata)
372
struct entry_pdata *pdata = entry_pdata;
374
return set_string(node, pdata->entry, gncEntrySetNotes);
378
entry_qty_handler (xmlNodePtr node, gpointer entry_pdata)
380
struct entry_pdata *pdata = entry_pdata;
382
return set_numeric(node, pdata->entry, gncEntrySetQuantity);
388
entry_invacct_handler (xmlNodePtr node, gpointer entry_pdata)
390
struct entry_pdata *pdata = entry_pdata;
391
return set_account (node, pdata, gncEntrySetInvAccount);
395
entry_iprice_handler (xmlNodePtr node, gpointer entry_pdata)
397
struct entry_pdata *pdata = entry_pdata;
399
return set_numeric(node, pdata->entry, gncEntrySetInvPrice);
403
entry_idiscount_handler (xmlNodePtr node, gpointer entry_pdata)
405
struct entry_pdata *pdata = entry_pdata;
407
return set_numeric(node, pdata->entry, gncEntrySetInvDiscount);
411
entry_idisctype_handler (xmlNodePtr node, gpointer entry_pdata)
413
struct entry_pdata *pdata = entry_pdata;
418
str = dom_tree_to_text (node);
419
g_return_val_if_fail (str, FALSE);
421
ret = gncAmountStringToType (str, &type);
425
gncEntrySetInvDiscountType(pdata->entry, type);
431
entry_idischow_handler (xmlNodePtr node, gpointer entry_pdata)
433
struct entry_pdata *pdata = entry_pdata;
438
str = dom_tree_to_text (node);
439
g_return_val_if_fail (str, FALSE);
441
ret = gncEntryDiscountStringToHow (str, &how);
445
gncEntrySetInvDiscountHow(pdata->entry, how);
451
entry_itaxable_handler (xmlNodePtr node, gpointer entry_pdata)
453
struct entry_pdata *pdata = entry_pdata;
454
return set_boolean (node, pdata->entry, gncEntrySetInvTaxable);
458
entry_itaxincluded_handler (xmlNodePtr node, gpointer entry_pdata)
460
struct entry_pdata *pdata = entry_pdata;
461
return set_boolean (node, pdata->entry, gncEntrySetInvTaxIncluded);
465
entry_itaxtable_handler (xmlNodePtr node, gpointer entry_pdata)
467
struct entry_pdata *pdata = entry_pdata;
468
return set_taxtable (node, pdata, gncEntrySetInvTaxTable);
474
entry_billacct_handler (xmlNodePtr node, gpointer entry_pdata)
476
struct entry_pdata *pdata = entry_pdata;
477
return set_account (node, pdata, gncEntrySetBillAccount);
481
entry_bprice_handler (xmlNodePtr node, gpointer entry_pdata)
483
struct entry_pdata *pdata = entry_pdata;
485
return set_numeric(node, pdata->entry, gncEntrySetBillPrice);
489
entry_btaxable_handler (xmlNodePtr node, gpointer entry_pdata)
491
struct entry_pdata *pdata = entry_pdata;
492
return set_boolean (node, pdata->entry, gncEntrySetBillTaxable);
496
entry_btaxincluded_handler (xmlNodePtr node, gpointer entry_pdata)
498
struct entry_pdata *pdata = entry_pdata;
499
return set_boolean (node, pdata->entry, gncEntrySetBillTaxIncluded);
503
entry_btaxtable_handler (xmlNodePtr node, gpointer entry_pdata)
505
struct entry_pdata *pdata = entry_pdata;
506
return set_taxtable (node, pdata, gncEntrySetBillTaxTable);
510
entry_billable_handler (xmlNodePtr node, gpointer entry_pdata)
512
struct entry_pdata *pdata = entry_pdata;
513
return set_boolean (node, pdata->entry, gncEntrySetBillable);
517
entry_billto_handler (xmlNodePtr node, gpointer entry_pdata)
519
struct entry_pdata *pdata = entry_pdata;
523
ret = gnc_dom_tree_to_owner (node, &billto, pdata->book);
525
gncEntrySetBillTo (pdata->entry, &billto);
532
entry_billpayment_handler (xmlNodePtr node, gpointer entry_pdata)
534
struct entry_pdata *pdata = entry_pdata;
535
GncEntryPaymentType type;
539
str = dom_tree_to_text (node);
540
g_return_val_if_fail (str, FALSE);
542
ret = gncEntryPaymentStringToType (str, &type);
546
gncEntrySetBillPayment(pdata->entry, type);
551
/* The rest of the stuff */
554
entry_order_handler (xmlNodePtr node, gpointer entry_pdata)
556
struct entry_pdata *pdata = entry_pdata;
560
guid = dom_tree_to_guid (node);
561
g_return_val_if_fail (guid, FALSE);
562
order = gncOrderLookup (pdata->book, guid);
564
order = gncOrderCreate (pdata->book);
565
gncOrderBeginEdit (order);
566
gncOrderSetGUID (order, guid);
567
gncOrderCommitEdit (order);
569
gncOrderBeginEdit (order);
570
gncOrderAddEntry (order, pdata->entry);
571
gncOrderCommitEdit (order);
578
entry_invoice_handler (xmlNodePtr node, gpointer entry_pdata)
580
struct entry_pdata *pdata = entry_pdata;
584
guid = dom_tree_to_guid (node);
585
g_return_val_if_fail (guid, FALSE);
586
invoice = gncInvoiceLookup (pdata->book, guid);
588
invoice = gncInvoiceCreate (pdata->book);
589
gncInvoiceBeginEdit (invoice);
590
gncInvoiceSetGUID (invoice, guid);
591
gncInvoiceCommitEdit (invoice);
593
gncInvoiceBeginEdit (invoice);
594
gncInvoiceAddEntry (invoice, pdata->entry);
595
gncInvoiceCommitEdit (invoice);
602
entry_bill_handler (xmlNodePtr node, gpointer entry_pdata)
604
struct entry_pdata *pdata = entry_pdata;
608
guid = dom_tree_to_guid (node);
609
g_return_val_if_fail (guid, FALSE);
610
invoice = gncInvoiceLookup (pdata->book, guid);
612
invoice = gncInvoiceCreate (pdata->book);
613
gncInvoiceBeginEdit (invoice);
614
gncInvoiceSetGUID (invoice, guid);
615
gncInvoiceCommitEdit (invoice);
617
gncInvoiceBeginEdit (invoice);
618
gncBillAddEntry (invoice, pdata->entry);
619
gncInvoiceCommitEdit (invoice);
625
/* Support for older XML versions */
628
entry_acct_handler (xmlNodePtr node, gpointer entry_pdata)
630
struct entry_pdata *pdata = entry_pdata;
631
/* XXX: try to figure out if this is an 'invoice' or a 'bill' --
632
* we have to wait until the end!
635
return set_account (node, pdata, NULL);
639
entry_price_handler (xmlNodePtr node, gpointer entry_pdata)
641
struct entry_pdata *pdata = entry_pdata;
644
/* just set both.. Don't worry about extra data if it's wrong */
645
res = set_numeric(node, pdata->entry, gncEntrySetInvPrice);
647
gncEntrySetBillPrice (pdata->entry, gncEntryGetInvPrice (pdata->entry));
652
entry_slots_handler (xmlNodePtr node, gpointer entry_pdata)
657
static struct dom_tree_handler entry_handlers_v2[] = {
658
{ entry_guid_string, entry_guid_handler, 1, 0 },
659
{ entry_date_string, entry_date_handler, 1, 0 },
660
{ entry_dateentered_string, entry_dateentered_handler, 1, 0 },
661
{ entry_description_string, entry_description_handler, 0, 0 },
662
{ entry_action_string, entry_action_handler, 0, 0 },
663
{ entry_notes_string, entry_notes_handler, 0, 0 },
664
{ entry_qty_string, entry_qty_handler, 0, 0 },
667
{ entry_invacct_string, entry_invacct_handler, 0, 0 },
668
{ entry_iprice_string, entry_iprice_handler, 0, 0 },
669
{ entry_idiscount_string, entry_idiscount_handler, 0, 0 },
670
{ entry_idisctype_string, entry_idisctype_handler, 0, 0 },
671
{ entry_idischow_string, entry_idischow_handler, 0, 0 },
672
{ entry_itaxable_string, entry_itaxable_handler, 0, 0 },
673
{ entry_itaxincluded_string, entry_itaxincluded_handler, 0, 0 },
674
{ entry_itaxtable_string, entry_itaxtable_handler, 0, 0 },
677
{ entry_billacct_string, entry_billacct_handler, 0, 0 },
678
{ entry_bprice_string, entry_bprice_handler, 0, 0 },
679
{ entry_btaxable_string, entry_btaxable_handler, 0, 0 },
680
{ entry_btaxincluded_string, entry_btaxincluded_handler, 0, 0 },
681
{ entry_btaxtable_string, entry_btaxtable_handler, 0, 0 },
682
{ entry_billable_string, entry_billable_handler, 0, 0 },
683
{ entry_billto_string, entry_billto_handler, 0, 0 },
686
{ entry_billpayment_string, entry_billpayment_handler, 0, 0 },
689
{ entry_order_string, entry_order_handler, 0, 0 },
690
{ entry_invoice_string, entry_invoice_handler, 0, 0 },
691
{ entry_bill_string, entry_bill_handler, 0, 0 },
692
{ entry_slots_string, entry_slots_handler, 0, 0 },
694
/* Old XML support */
695
{ "entry:acct", entry_acct_handler, 0, 0 },
696
{ "entry:price", entry_price_handler, 0, 0 },
697
{ "entry:discount", entry_idiscount_handler, 0, 0 },
698
{ "entry:disc-type", entry_idisctype_handler, 0, 0 },
699
{ "entry:disc-how", entry_idischow_handler, 0, 0 },
700
{ "entry:taxable", entry_itaxable_handler, 0, 0 },
701
{ "entry:taxincluded", entry_itaxincluded_handler, 0, 0 },
702
{ "entry:taxtable", entry_itaxtable_handler, 0, 0 },
707
dom_tree_to_entry (xmlNodePtr node, QofBook *book)
709
struct entry_pdata entry_pdata;
712
entry_pdata.entry = gncEntryCreate(book);
713
entry_pdata.book = book;
714
entry_pdata.acc = NULL;
715
gncEntryBeginEdit (entry_pdata.entry);
717
successful = dom_tree_generic_parse (node, entry_handlers_v2,
719
if (entry_pdata.acc != NULL) {
720
if (gncEntryGetBill (entry_pdata.entry))
721
gncEntrySetBillAccount (entry_pdata.entry, entry_pdata.acc);
723
gncEntrySetInvAccount (entry_pdata.entry, entry_pdata.acc);
727
gncEntryCommitEdit (entry_pdata.entry);
730
PERR ("failed to parse entry tree");
731
gncEntryDestroy (entry_pdata.entry);
732
entry_pdata.entry = NULL;
735
return entry_pdata.entry;
739
gnc_entry_end_handler(gpointer data_for_children,
740
GSList* data_from_children, GSList* sibling_data,
741
gpointer parent_data, gpointer global_data,
742
gpointer *result, const gchar *tag)
746
xmlNodePtr tree = (xmlNodePtr)data_for_children;
747
gxpf_data *gdata = (gxpf_data*)global_data;
748
QofBook *book = gdata->bookdata;
757
/* OK. For some messed up reason this is getting called again with a
758
NULL tag. So we ignore those cases */
764
g_return_val_if_fail(tree, FALSE);
766
entry = dom_tree_to_entry(tree, book);
769
gdata->cb(tag, gdata->parsedata, entry);
774
return entry != NULL;
778
entry_sixtp_parser_create(void)
780
return sixtp_dom_parser_new(gnc_entry_end_handler, NULL, NULL);
784
do_count (QofInstance * entry_p, gpointer count_p)
786
int *count = count_p;
791
entry_get_count (QofBook *book)
794
qof_object_foreach (_GNC_MOD_NAME, book, do_count, (gpointer) &count);
799
xml_add_entry (QofInstance * entry_p, gpointer out_p)
802
GncEntry *entry = (GncEntry *) entry_p;
805
/* Don't save non-attached entries! */
806
if (!(gncEntryGetOrder (entry) || gncEntryGetInvoice (entry) ||
807
gncEntryGetBill (entry)))
810
node = entry_dom_tree_create (entry);
811
xmlElemDump(out, NULL, node);
817
entry_write (FILE *out, QofBook *book)
819
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_entry, (gpointer) out);
825
g_return_if_fail(out);
826
gnc_xml2_write_namespace_decl(out, "entry");
830
gnc_entry_xml_initialize (void)
832
static GncXmlDataType_t be_data = {
833
GNC_FILE_BACKEND_VERS,
835
entry_sixtp_parser_create,
843
qof_object_register_backend (_GNC_MOD_NAME,