GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-transaction-xml-v2.cpp
1/********************************************************************
2 * gnc-transactions-xml-v2.c -- xml routines for transactions *
3 * Copyright (C) 2001 Rob Browning *
4 * Copyright (C) 2002 Linas Vepstas <linas@linas.org> *
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 <string.h>
28#include "AccountP.hpp"
29#include "Transaction.h"
30#include "TransactionP.hpp"
31#include "gnc-lot.h"
32#include "gnc-lot-p.h"
33
34#include "gnc-xml-helper.h"
35
36#include "sixtp.h"
37#include "sixtp-utils.h"
38#include "sixtp-parsers.h"
39#include "sixtp-utils.h"
40#include "sixtp-dom-parsers.h"
41#include "sixtp-dom-generators.h"
42
43#include "gnc-xml.h"
44
45#include "io-gncxml-gen.h"
46
47#include "sixtp-dom-parsers.h"
48
49[[maybe_unused]] static const QofLogModule log_module = G_LOG_DOMAIN;
50const gchar* transaction_version_string = "2.0.0";
51
52static void
53add_gnc_num (xmlNodePtr node, const gchar* tag, gnc_numeric num)
54{
55 xmlAddChild (node, gnc_numeric_to_dom_tree (tag, &num));
56}
57
58static void
59add_time64 (xmlNodePtr node, const gchar * tag, time64 time, gboolean always)
60{
61 if (always || time)
62 xmlAddChild (node, time64_to_dom_tree (tag, time));
63}
64
65static xmlNodePtr
66split_to_dom_tree (const gchar* tag, Split* spl)
67{
68 xmlNodePtr ret;
69
70 ret = xmlNewNode (NULL, BAD_CAST tag);
71
72 xmlAddChild (ret, guid_to_dom_tree ("split:id", xaccSplitGetGUID (spl)));
73
74 {
75 char* memo = g_strdup (xaccSplitGetMemo (spl));
76
77 if (memo && g_strcmp0 (memo, "") != 0)
78 {
79 xmlNewTextChild (ret, NULL, BAD_CAST "split:memo",
80 checked_char_cast (memo));
81 }
82 g_free (memo);
83 }
84
85 {
86 char* action = g_strdup (xaccSplitGetAction (spl));
87
88 if (action && g_strcmp0 (action, "") != 0)
89 {
90 xmlNewTextChild (ret, NULL, BAD_CAST "split:action",
91 checked_char_cast (action));
92 }
93 g_free (action);
94 }
95
96 {
97 char tmp[2];
98
99 tmp[0] = xaccSplitGetReconcile (spl);
100 tmp[1] = '\0';
101
102 xmlNewTextChild (ret, NULL, BAD_CAST "split:reconciled-state",
103 BAD_CAST tmp);
104 }
105
106 add_time64 (ret, "split:reconcile-date",
107 xaccSplitGetDateReconciled (spl), FALSE);
108
109 add_gnc_num (ret, "split:value", xaccSplitGetValue (spl));
110
111 add_gnc_num (ret, "split:quantity", xaccSplitGetAmount (spl));
112
113 {
114 Account* account = xaccSplitGetAccount (spl);
115
116 xmlAddChild (ret, guid_to_dom_tree ("split:account",
117 xaccAccountGetGUID (account)));
118 }
119 {
120 GNCLot* lot = xaccSplitGetLot (spl);
121
122 if (lot)
123 {
124 xmlAddChild (ret, guid_to_dom_tree ("split:lot",
125 gnc_lot_get_guid (lot)));
126 }
127 }
128 /* xmlAddChild won't do anything with a NULL, so tests are superfluous. */
129 xmlAddChild (ret, qof_instance_slots_to_dom_tree ("split:slots",
130 QOF_INSTANCE (spl)));
131 return ret;
132}
133
134static void
135add_trans_splits (xmlNodePtr node, Transaction* trn)
136{
137 GList* n;
138 xmlNodePtr toaddto;
139
140 toaddto = xmlNewChild (node, NULL, BAD_CAST "trn:splits", NULL);
141
142 for (n = xaccTransGetSplitList (trn); n; n = n->next)
143 {
144 Split* s = static_cast<decltype (s)> (n->data);
145 xmlAddChild (toaddto, split_to_dom_tree ("trn:split", s));
146 }
147}
148
149xmlNodePtr
150gnc_transaction_dom_tree_create (Transaction* trn)
151{
152 xmlNodePtr ret;
153 gchar* str = NULL;
154
155 ret = xmlNewNode (NULL, BAD_CAST "gnc:transaction");
156
157 xmlSetProp (ret, BAD_CAST "version",
158 BAD_CAST transaction_version_string);
159
160 xmlAddChild (ret, guid_to_dom_tree ("trn:id", xaccTransGetGUID (trn)));
161
162 xmlAddChild (ret, commodity_ref_to_dom_tree ("trn:currency",
163 xaccTransGetCurrency (trn)));
164 str = g_strdup (xaccTransGetNum (trn));
165 if (str && (g_strcmp0 (str, "") != 0))
166 {
167 xmlNewTextChild (ret, NULL, BAD_CAST "trn:num",
168 checked_char_cast (str));
169 }
170 g_free (str);
171
172 add_time64 (ret, "trn:date-posted", xaccTransRetDatePosted (trn), TRUE);
173
174 add_time64 (ret, "trn:date-entered",
175 xaccTransRetDateEntered (trn), TRUE);
176
177 str = g_strdup (xaccTransGetDescription (trn));
178 if (str)
179 {
180 xmlNewTextChild (ret, NULL, BAD_CAST "trn:description",
181 checked_char_cast (str));
182 }
183 g_free (str);
184
185 /* xmlAddChild won't do anything with a NULL, so tests are superfluous. */
186 xmlAddChild (ret, qof_instance_slots_to_dom_tree ("trn:slots",
187 QOF_INSTANCE (trn)));
188
189 add_trans_splits (ret, trn);
190
191 return ret;
192}
193
194/***********************************************************************/
195
197{
198 Split* split;
199 QofBook* book;
200};
201
202static inline gboolean
203set_spl_gnc_num (xmlNodePtr node, Split* spl,
204 void (*func) (Split* spl, gnc_numeric gn))
205{
206 func (spl, dom_tree_to_gnc_numeric (node));
207 return TRUE;
208}
209
210static gboolean
211spl_id_handler (xmlNodePtr node, gpointer data)
212{
213 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
214 auto tmp = dom_tree_to_guid (node);
215 g_return_val_if_fail (tmp, FALSE);
216
217 xaccSplitSetGUID (pdata->split, &*tmp);
218
219 return TRUE;
220}
221
222static gboolean
223spl_memo_handler (xmlNodePtr node, gpointer data)
224{
225 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
226 return apply_xmlnode_text (xaccSplitSetMemo, pdata->split, node);
227}
228
229static gboolean
230spl_action_handler (xmlNodePtr node, gpointer data)
231{
232 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
233 return apply_xmlnode_text (xaccSplitSetAction, pdata->split, node);
234}
235
236static gboolean
237spl_reconciled_state_handler (xmlNodePtr node, gpointer data)
238{
239 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
240 auto set_reconciled = [](Split* s, const char *txt)
241 {
242 xaccSplitSetReconcile(s, txt[0]);
243 };
244 return apply_xmlnode_text (set_reconciled, pdata->split, node);
245}
246
247static gboolean
248spl_reconcile_date_handler (xmlNodePtr node, gpointer data)
249{
250 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
251 time64 time = dom_tree_to_time64 (node);
252 if (!dom_tree_valid_time64 (time, node->name)) time = 0;
253 xaccSplitSetDateReconciledSecs (pdata->split, time);
254 return TRUE;
255}
256
257static gboolean
258spl_value_handler (xmlNodePtr node, gpointer data)
259{
260 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
261 return set_spl_gnc_num (node, pdata->split, xaccSplitSetValue);
262}
263
264static gboolean
265spl_quantity_handler (xmlNodePtr node, gpointer data)
266{
267 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
268 return set_spl_gnc_num (node, pdata->split, xaccSplitSetAmount);
269}
270
271gboolean gnc_transaction_xml_v2_testing = FALSE;
272
273static gboolean
274spl_account_handler (xmlNodePtr node, gpointer data)
275{
276 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
277 auto id = dom_tree_to_guid (node);
278 Account* account;
279
280 g_return_val_if_fail (id, FALSE);
281
282 account = xaccAccountLookup (&*id, pdata->book);
283 if (!account && gnc_transaction_xml_v2_testing &&
284 !guid_equal (&*id, guid_null ()))
285 {
286 account = xaccMallocAccount (pdata->book);
287 xaccAccountSetGUID (account, &*id);
289 xaccSplitGetAmount (pdata->split).denom);
290 }
291
292 xaccAccountInsertSplit (account, pdata->split);
293
294 return TRUE;
295}
296
297static gboolean
298spl_lot_handler (xmlNodePtr node, gpointer data)
299{
300 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
301 auto id = dom_tree_to_guid (node);
302 GNCLot* lot;
303
304 g_return_val_if_fail (id, FALSE);
305
306 lot = gnc_lot_lookup (&*id, pdata->book);
307 if (!lot && gnc_transaction_xml_v2_testing &&
308 !guid_equal (&*id, guid_null ()))
309 {
310 lot = gnc_lot_new (pdata->book);
311 gnc_lot_set_guid (lot, *id);
312 }
313
314 gnc_lot_add_split (lot, pdata->split);
315
316 return TRUE;
317}
318
319static gboolean
320spl_slots_handler (xmlNodePtr node, gpointer data)
321{
322 struct split_pdata* pdata = static_cast<decltype (pdata)> (data);
323 gboolean successful;
324
325 successful = dom_tree_create_instance_slots (node,
326 QOF_INSTANCE (pdata->split));
327 g_return_val_if_fail (successful, FALSE);
328
329 return TRUE;
330}
331
332struct dom_tree_handler spl_dom_handlers[] =
333{
334 { "split:id", spl_id_handler, 1, 0 },
335 { "split:memo", spl_memo_handler, 0, 0 },
336 { "split:action", spl_action_handler, 0, 0 },
337 { "split:reconciled-state", spl_reconciled_state_handler, 1, 0 },
338 { "split:reconcile-date", spl_reconcile_date_handler, 0, 0 },
339 { "split:value", spl_value_handler, 1, 0 },
340 { "split:quantity", spl_quantity_handler, 1, 0 },
341 { "split:account", spl_account_handler, 1, 0 },
342 { "split:lot", spl_lot_handler, 0, 0 },
343 { "split:slots", spl_slots_handler, 0, 0 },
344 { NULL, NULL, 0, 0 },
345};
346
347static Split*
348dom_tree_to_split (xmlNodePtr node, QofBook* book)
349{
350 struct split_pdata pdata;
351 Split* ret;
352
353 g_return_val_if_fail (book, NULL);
354
355 ret = xaccMallocSplit (book);
356 g_return_val_if_fail (ret, NULL);
357
358 pdata.split = ret;
359 pdata.book = book;
360
361 /* this isn't going to work in a testing setup */
362 if (dom_tree_generic_parse (node, spl_dom_handlers, &pdata))
363 {
364 return ret;
365 }
366 else
367 {
368 xaccSplitDestroy (ret);
369 return NULL;
370 }
371}
372
373/***********************************************************************/
374
376{
377 Transaction* trans;
378 QofBook* book;
379};
380
381static gboolean
382set_tran_time64 (xmlNodePtr node, Transaction * trn,
383 void (*func) (Transaction *, time64))
384{
385 time64 time = dom_tree_to_time64 (node);
386 if (!dom_tree_valid_time64 (time, node->name)) time = 0;
387 func (trn, time);
388 return TRUE;
389}
390
391static gboolean
392trn_id_handler (xmlNodePtr node, gpointer trans_pdata)
393{
394 struct trans_pdata* pdata = static_cast<decltype (pdata)> (trans_pdata);
395 Transaction* trn = pdata->trans;
396 auto tmp = dom_tree_to_guid (node);
397
398 g_return_val_if_fail (tmp, FALSE);
399
400 xaccTransSetGUID ((Transaction*)trn, &*tmp);
401
402 return TRUE;
403}
404
405static gboolean
406trn_currency_handler (xmlNodePtr node, gpointer trans_pdata)
407{
408 struct trans_pdata* pdata = static_cast<decltype (pdata)> (trans_pdata);
409 Transaction* trn = pdata->trans;
410 gnc_commodity* ref;
411
412 ref = dom_tree_to_commodity_ref (node, pdata->book);
413 xaccTransSetCurrency (trn, ref);
414
415 return TRUE;
416}
417
418static gboolean
419trn_num_handler (xmlNodePtr node, gpointer trans_pdata)
420{
421 struct trans_pdata* pdata = static_cast<decltype (pdata)> (trans_pdata);
422 Transaction* trn = pdata->trans;
423
424 return apply_xmlnode_text (xaccTransSetNum, trn, node);
425}
426
427static gboolean
428trn_date_posted_handler (xmlNodePtr node, gpointer trans_pdata)
429{
430 struct trans_pdata* pdata = static_cast<decltype (pdata)> (trans_pdata);
431 Transaction* trn = pdata->trans;
432
433 return set_tran_time64 (node, trn, xaccTransSetDatePostedSecs);
434}
435
436static gboolean
437trn_date_entered_handler (xmlNodePtr node, gpointer trans_pdata)
438{
439 struct trans_pdata* pdata = static_cast<decltype (pdata)> (trans_pdata);
440 Transaction* trn = pdata->trans;
441
442 return set_tran_time64 (node, trn, xaccTransSetDateEnteredSecs);
443}
444
445static gboolean
446trn_description_handler (xmlNodePtr node, gpointer trans_pdata)
447{
448 struct trans_pdata* pdata = static_cast<decltype (pdata)> (trans_pdata);
449 Transaction* trn = pdata->trans;
450
451 return apply_xmlnode_text (xaccTransSetDescription, trn, node);
452}
453
454static gboolean
455trn_slots_handler (xmlNodePtr node, gpointer trans_pdata)
456{
457 struct trans_pdata* pdata = static_cast<decltype (pdata)> (trans_pdata);
458 Transaction* trn = pdata->trans;
459 gboolean successful;
460
461 successful = dom_tree_create_instance_slots (node, QOF_INSTANCE (trn));
462
463 g_return_val_if_fail (successful, FALSE);
464
465 return TRUE;
466}
467
468static gboolean
469trn_splits_handler (xmlNodePtr node, gpointer trans_pdata)
470{
471 struct trans_pdata* pdata = static_cast<decltype (pdata)> (trans_pdata);
472 Transaction* trn = pdata->trans;
473 xmlNodePtr mark;
474
475 g_return_val_if_fail (node, FALSE);
476 g_return_val_if_fail (node->xmlChildrenNode, FALSE);
477
478 for (mark = node->xmlChildrenNode; mark; mark = mark->next)
479 {
480 Split* spl;
481
482 if (g_strcmp0 ("text", (char*)mark->name) == 0)
483 continue;
484
485 if (g_strcmp0 ("trn:split", (char*)mark->name))
486 {
487 return FALSE;
488 }
489
490 spl = dom_tree_to_split (mark, pdata->book);
491
492 if (spl)
493 {
494 xaccTransAppendSplit (trn, spl);
495 }
496 else
497 {
498 return FALSE;
499 }
500 }
501 return TRUE;
502}
503
504struct dom_tree_handler trn_dom_handlers[] =
505{
506 { "trn:id", trn_id_handler, 1, 0 },
507 { "trn:currency", trn_currency_handler, 0, 0},
508 { "trn:num", trn_num_handler, 0, 0 },
509 { "trn:date-posted", trn_date_posted_handler, 1, 0 },
510 { "trn:date-entered", trn_date_entered_handler, 1, 0 },
511 { "trn:description", trn_description_handler, 0, 0 },
512 { "trn:slots", trn_slots_handler, 0, 0 },
513 { "trn:splits", trn_splits_handler, 1, 0 },
514 { NULL, NULL, 0, 0 },
515};
516
517static gboolean
518gnc_transaction_end_handler (gpointer data_for_children,
519 GSList* data_from_children, GSList* sibling_data,
520 gpointer parent_data, gpointer global_data,
521 gpointer* result, const gchar* tag)
522{
523 Transaction* trn = NULL;
524 xmlNodePtr tree = (xmlNodePtr)data_for_children;
525 gxpf_data* gdata = (gxpf_data*)global_data;
526
527 if (parent_data)
528 {
529 return TRUE;
530 }
531
532 /* OK. For some messed up reason this is getting called again with a
533 NULL tag. So we ignore those cases */
534 if (!tag)
535 {
536 return TRUE;
537 }
538
539 g_return_val_if_fail (tree, FALSE);
540
541 trn = dom_tree_to_transaction (tree,
542 static_cast<QofBook*> (gdata->bookdata));
543 if (trn != NULL)
544 {
545 gdata->cb (tag, gdata->parsedata, trn);
546 }
547
548 xmlFreeNode (tree);
549
550 return trn != NULL;
551}
552
553Transaction*
554dom_tree_to_transaction (xmlNodePtr node, QofBook* book)
555{
556 Transaction* trn;
557 gboolean successful;
558 struct trans_pdata pdata;
559
560 g_return_val_if_fail (node, NULL);
561 g_return_val_if_fail (book, NULL);
562
563 trn = xaccMallocTransaction (book);
564 g_return_val_if_fail (trn, NULL);
565 xaccTransBeginEdit (trn);
566
567 pdata.trans = trn;
568 pdata.book = book;
569
570 successful = dom_tree_generic_parse (node, trn_dom_handlers, &pdata);
571
573
574 if (!successful)
575 {
576 xmlElemDump (stdout, NULL, node);
577 xaccTransBeginEdit (trn);
578 xaccTransDestroy (trn);
580 trn = NULL;
581 }
582
583 return trn;
584}
585
586sixtp*
587gnc_transaction_sixtp_parser_create (void)
588{
589 return sixtp_dom_parser_new (gnc_transaction_end_handler, NULL, NULL);
590}
This is the private header for the account structure.
API for Transactions and Splits (journal entries)
void xaccAccountSetCommoditySCU(Account *acc, int scu)
Set the SCU for the account.
Definition Account.cpp:2722
#define xaccAccountGetGUID(X)
Definition Account.h:252
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition Account.cpp:1270
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
Definition Account.cpp:2050
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
time64 xaccTransRetDateEntered(const Transaction *trans)
Retrieve the date of when the transaction was entered.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
void xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly,...
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
#define xaccTransGetGUID(X)
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction,...
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
const char * xaccTransGetNum(const Transaction *trans)
Gets the transaction Number (or ID) field; rather than use this function directly,...
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account.
Definition Account.h:1069
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition guid.cpp:165
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
Definition guid.cpp:237
void gnc_lot_add_split(GNCLot *lot, Split *split)
Adds a split to this lot.
Definition gnc-lot.cpp:579
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition Split.cpp:1506
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
#define xaccSplitGetGUID(X)
Definition Split.h:579
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
Split * xaccMallocSplit(QofBook *book)
Constructor.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
const char * xaccSplitGetAction(const Split *split)
Returns the action string.
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn't be...
Definition Split.cpp:1920
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition Split.cpp:1859
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64.
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition Split.cpp:1786
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
STRUCTS.
QofBook reference.
Definition qofbook-p.hpp:47
Definition sixtp.h:130