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"
43 #include "io-gncxml-gen.h"
45 #include "sixtp-dom-parsers.h"
48 #define G_LOG_DOMAIN "gnc.backend.file.sx"
51 #define SX_NAME "sx:name"
52 #define SX_ENABLED "sx:enabled"
53 #define SX_AUTOCREATE "sx:autoCreate"
54 #define SX_AUTOCREATE_NOTIFY "sx:autoCreateNotify"
55 #define SX_ADVANCE_CREATE_DAYS "sx:advanceCreateDays"
56 #define SX_ADVANCE_REMIND_DAYS "sx:advanceRemindDays"
57 #define SX_INSTANCE_COUNT "sx:instanceCount"
58 #define SX_START "sx:start"
59 #define SX_LAST "sx:last"
60 #define SX_NUM_OCCUR "sx:num-occur"
61 #define SX_REM_OCCUR "sx:rem-occur"
62 #define SX_END "sx:end"
63 #define SX_TEMPL_ACCT "sx:templ-acct"
64 #define SX_FREQSPEC "sx:freqspec"
65 #define SX_SCHEDULE "sx:schedule"
66 #define SX_SLOTS "sx:slots"
67 #define SX_DEFER_INSTANCE "sx:deferredInstance"
73 #define GNC_ACCOUNT_TAG "gnc:account"
74 #define GNC_TRANSACTION_TAG "gnc:transaction"
75 #define GNC_SCHEDXACTION_TAG "gnc:schedxaction"
77 const gchar *schedxaction_version_string =
"1.0.0";
78 const gchar *schedxaction_version2_string =
"2.0.0";
87 gboolean allow_2_2_incompat = TRUE;
88 gchar *name = g_strdup (xaccSchedXactionGetName(sx));
93 ret = xmlNewNode (NULL, BAD_CAST GNC_SCHEDXACTION_TAG);
95 if (allow_2_2_incompat)
96 xmlSetProp(ret, BAD_CAST
"version", BAD_CAST schedxaction_version2_string);
98 xmlSetProp(ret, BAD_CAST
"version", BAD_CAST schedxaction_version_string);
101 guid_to_dom_tree(SX_ID,
104 xmlNewTextChild( ret, NULL, BAD_CAST SX_NAME, checked_char_cast (name));
107 if (allow_2_2_incompat)
109 xmlNewTextChild( ret, NULL, BAD_CAST SX_ENABLED,
110 BAD_CAST ( sx->enabled ?
"y" :
"n" ) );
113 xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE,
114 BAD_CAST ( sx->autoCreateOption ?
"y" :
"n" ) );
115 xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY,
116 BAD_CAST ( sx->autoCreateNotify ?
"y" :
"n" ) );
117 xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_CREATE_DAYS,
118 sx->advanceCreateDays));
119 xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_REMIND_DAYS,
120 sx->advanceRemindDays));
123 xmlAddChild( ret, int_to_dom_tree( SX_INSTANCE_COUNT,
127 gdate_to_dom_tree( SX_START,
128 xaccSchedXactionGetStartDate(sx) ) );
130 date = xaccSchedXactionGetLastOccurDate(sx);
131 if ( g_date_valid( date ) )
133 xmlAddChild( ret, gdate_to_dom_tree( SX_LAST, date ) );
139 xmlAddChild(ret, int_to_dom_tree( SX_NUM_OCCUR,
140 xaccSchedXactionGetNumOccur(sx)));
141 xmlAddChild(ret, int_to_dom_tree( SX_REM_OCCUR,
142 xaccSchedXactionGetRemOccur(sx)));
145 else if ( xaccSchedXactionHasEndDate(sx) )
148 gdate_to_dom_tree( SX_END,
154 guid_to_dom_tree(SX_TEMPL_ACCT,
157 if (allow_2_2_incompat)
159 xmlNodePtr schedule_node = xmlNewNode(NULL,
160 BAD_CAST
"sx:schedule");
162 for (; schedule != NULL; schedule = schedule->next)
164 xmlAddChild(schedule_node, recurrence_to_dom_tree(
"gnc:recurrence", (
Recurrence*)schedule->data));
166 xmlAddChild(ret, schedule_node);
179 instNode = xmlNewNode( NULL, BAD_CAST SX_DEFER_INSTANCE );
180 if ( g_date_valid( &tsd->last_date ) )
182 xmlAddChild( instNode, gdate_to_dom_tree( SX_LAST,
185 xmlAddChild( instNode, int_to_dom_tree( SX_REM_OCCUR,
186 tsd->num_occur_rem ) );
187 xmlAddChild( instNode, int_to_dom_tree( SX_INSTANCE_COUNT,
189 xmlAddChild( ret, instNode );
196 kvp_frame_to_dom_tree( SX_SLOTS,
200 xmlAddChild(ret, kvpnode);
211 gboolean saw_freqspec;
212 gboolean saw_recurrence;
217 sx_id_handler( xmlNodePtr node, gpointer
sx_pdata )
219 struct sx_pdata *pdata = sx_pdata;
221 GncGUID *tmp = dom_tree_to_guid( node );
223 g_return_val_if_fail( tmp, FALSE );
224 xaccSchedXactionSetGUID(sx, tmp);
232 sx_name_handler( xmlNodePtr node, gpointer
sx_pdata )
234 struct sx_pdata *pdata = sx_pdata;
236 gchar *tmp = dom_tree_to_text( node );
237 g_debug(
"sx named [%s]", tmp);
238 g_return_val_if_fail( tmp, FALSE );
245 sx_enabled_handler( xmlNodePtr node, gpointer
sx_pdata )
247 struct sx_pdata *pdata = sx_pdata;
249 gchar *tmp = dom_tree_to_text( node );
251 sx->enabled = (g_strcmp0( tmp,
"y" ) == 0 ? TRUE : FALSE );
257 sx_autoCreate_handler( xmlNodePtr node, gpointer
sx_pdata )
259 struct sx_pdata *pdata = sx_pdata;
261 gchar *tmp = dom_tree_to_text( node );
263 sx->autoCreateOption = (g_strcmp0( tmp,
"y" ) == 0 ? TRUE : FALSE );
269 sx_notify_handler( xmlNodePtr node, gpointer
sx_pdata )
271 struct sx_pdata *pdata = sx_pdata;
273 gchar *tmp = dom_tree_to_text( node );
275 sx->autoCreateNotify = (g_strcmp0( tmp,
"y" ) == 0 ? TRUE : FALSE );
281 sx_advCreate_handler( xmlNodePtr node, gpointer
sx_pdata )
283 struct sx_pdata *pdata = sx_pdata;
287 if ( ! dom_tree_to_integer( node, &advCreate ) )
292 xaccSchedXactionSetAdvanceCreation( sx, advCreate );
297 sx_advRemind_handler( xmlNodePtr node, gpointer sx_pdata )
299 struct sx_pdata *pdata = sx_pdata;
303 if ( ! dom_tree_to_integer( node, &advRemind ) )
308 xaccSchedXactionSetAdvanceReminder( sx, advRemind );
318 date = dom_tree_to_gdate( node );
319 g_return_val_if_fail( date, FALSE );
320 (*settor)( sx, date );
328 sx_instcount_handler( xmlNodePtr node, gpointer sx_pdata )
330 struct sx_pdata *pdata = sx_pdata;
334 if ( ! dom_tree_to_integer( node, &instanceNum ) )
345 sx_start_handler( xmlNodePtr node, gpointer sx_pdata )
347 struct sx_pdata *pdata = sx_pdata;
350 return sx_set_date( node, sx, xaccSchedXactionSetStartDate );
355 sx_last_handler( xmlNodePtr node, gpointer sx_pdata )
357 struct sx_pdata *pdata = sx_pdata;
360 return sx_set_date( node, sx, xaccSchedXactionSetLastOccurDate );
365 sx_end_handler( xmlNodePtr node, gpointer sx_pdata )
367 struct sx_pdata *pdata = sx_pdata;
374 _fixup_recurrence_start_dates(
const GDate *sx_start_date, GList *schedule)
377 for (iter = schedule; iter != NULL; iter = iter->next)
384 start = *sx_start_date;
385 g_date_subtract_days(&start, 1);
387 g_date_clear(&next, 1);
389 recurrenceNextInstance(r, &start, &next);
390 g_return_if_fail(g_date_valid(&next));
396 g_date_strftime(date_str, 127,
"%x", &next);
397 sched_str = recurrenceToString(r);
398 g_debug(
"setting recurrence [%s] start date to [%s]",
399 sched_str, date_str);
404 recurrenceGetMultiplier(r),
405 recurrenceGetPeriodType(r),
407 recurrenceGetWeekendAdjust(r));
410 if (g_list_length(schedule) == 1
411 && recurrenceGetPeriodType((
Recurrence*)g_list_nth_data(schedule, 0)) == PERIOD_ONCE)
415 g_date_strftime(date_buf, 127,
"%x", sx_start_date);
416 recurrenceSet(fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE);
417 g_debug(
"fixed up period=ONCE Recurrence to date [%s]", date_buf);
422 sx_freqspec_handler( xmlNodePtr node, gpointer sx_pdata )
424 struct sx_pdata *pdata = sx_pdata;
429 g_return_val_if_fail( node, FALSE );
431 schedule = dom_tree_freqSpec_to_recurrences(node, pdata->book);
433 debug_str = recurrenceListToString(schedule);
434 g_debug(
"parsed from freqspec [%s]", debug_str);
437 _fixup_recurrence_start_dates(xaccSchedXactionGetStartDate(sx), schedule);
438 pdata->saw_freqspec = TRUE;
444 sx_schedule_recurrence_handler(xmlNodePtr node, gpointer parsing_data)
446 GList **schedule = (GList**)parsing_data;
449 g_return_val_if_fail(r, FALSE);
450 sched_str = recurrenceToString(r);
451 g_debug(
"parsed recurrence [%s]", sched_str);
453 *schedule = g_list_append(*schedule, r);
459 {
"gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 },
464 sx_recurrence_handler(xmlNodePtr node, gpointer _pdata)
466 struct sx_pdata *parsing_data = _pdata;
467 GList *schedule = NULL;
470 g_return_val_if_fail(node, FALSE);
472 if (!dom_tree_generic_parse(node, sx_recurrence_list_handlers, &schedule))
475 debug_str = recurrenceListToString(schedule);
476 g_debug(
"setting freshly-parsed schedule: [%s]", debug_str);
479 parsing_data->saw_recurrence = TRUE;
485 sx_defer_last_handler( xmlNodePtr node, gpointer gpTSD )
490 g_return_val_if_fail( node, FALSE );
491 gd = dom_tree_to_gdate( node );
492 g_return_val_if_fail( gd, FALSE );
493 tsd->last_date = *gd;
500 sx_defer_rem_occur_handler( xmlNodePtr node, gpointer gpTSD )
504 g_return_val_if_fail( node, FALSE );
506 if ( ! dom_tree_to_integer( node, &remOccur ) )
510 tsd->num_occur_rem = remOccur;
516 sx_defer_inst_count_handler( xmlNodePtr node, gpointer gpTSD )
520 g_return_val_if_fail( node, FALSE );
522 if ( ! dom_tree_to_integer( node, &instCount ) )
526 tsd->num_inst = instCount;
533 { SX_LAST, sx_defer_last_handler, 1, 0 },
534 { SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 },
535 { SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 },
541 sx_defer_inst_handler( xmlNodePtr node, gpointer sx_pdata )
543 struct sx_pdata *pdata = sx_pdata;
547 g_return_val_if_fail( node, FALSE );
550 g_assert( sx_defer_dom_handlers != NULL );
551 if ( !dom_tree_generic_parse( node,
552 sx_defer_dom_handlers,
555 xmlElemDump(stdout, NULL, node);
568 sx_numOccur_handler( xmlNodePtr node, gpointer sx_pdata )
570 struct sx_pdata *pdata = sx_pdata;
574 if ( ! dom_tree_to_integer( node, &numOccur ) )
587 sx_templ_acct_handler( xmlNodePtr node, gpointer sx_pdata)
589 struct sx_pdata *pdata = sx_pdata;
591 GncGUID *templ_acct_guid = dom_tree_to_guid(node);
594 if (!templ_acct_guid)
600 sx_set_template_account(sx, account);
601 g_free(templ_acct_guid);
609 sx_remOccur_handler( xmlNodePtr node, gpointer sx_pdata )
611 struct sx_pdata *pdata = sx_pdata;
615 if ( ! dom_tree_to_integer( node, &remOccur ) )
620 xaccSchedXactionSetRemOccur( sx, remOccur );
627 sx_slots_handler( xmlNodePtr node, gpointer sx_pdata )
629 struct sx_pdata *pdata = sx_pdata;
637 { SX_ID, sx_id_handler, 1, 0 },
638 { SX_NAME, sx_name_handler, 1, 0 },
639 { SX_ENABLED, sx_enabled_handler, 0, 0 },
640 { SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 },
641 { SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
642 { SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
643 { SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
644 { SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
645 { SX_START, sx_start_handler, 1, 0 },
646 { SX_LAST, sx_last_handler, 0, 0 },
647 { SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },
648 { SX_REM_OCCUR, sx_remOccur_handler, 0, 0 },
649 { SX_END, sx_end_handler, 0, 0 },
650 { SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 },
651 { SX_FREQSPEC, sx_freqspec_handler, 0, 0 },
652 { SX_SCHEDULE, sx_recurrence_handler, 0, 0 },
653 { SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 },
654 { SX_SLOTS, sx_slots_handler, 0, 0 },
659 gnc_schedXaction_end_handler(gpointer data_for_children,
660 GSList* data_from_children, GSList* sibling_data,
661 gpointer parent_data, gpointer global_data,
662 gpointer *result,
const gchar *tag)
665 gboolean successful = FALSE;
666 xmlNodePtr tree = (xmlNodePtr)data_for_children;
668 struct sx_pdata sx_pdata;
680 g_return_val_if_fail( tree, FALSE );
684 memset(&sx_pdata, 0,
sizeof(sx_pdata));
686 sx_pdata.book = gdata->bookdata;
688 g_assert( sx_dom_handlers != NULL );
690 successful = dom_tree_generic_parse( tree, sx_dom_handlers, &sx_pdata );
693 g_critical(
"failed to parse scheduled xaction");
694 xmlElemDump( stdout, NULL, tree );
695 gnc_sx_begin_edit( sx );
700 if (tree->properties)
702 gchar *sx_name = xaccSchedXactionGetName(sx);
704 for (attr = tree->properties; attr != NULL; attr = attr->next)
706 xmlChar *attr_value = attr->children->content;
707 g_debug(
"sx attribute name[%s] value[%s]", attr->name, attr_value);
708 if (strcmp((
const char *)attr->name,
"version") != 0)
710 g_warning(
"unknown sx attribute [%s]", attr->name);
716 if (strcmp((
const char *)attr_value,
717 schedxaction_version_string) == 0)
719 if (!sx_pdata.saw_freqspec)
720 g_critical(
"did not see freqspec in version 1 sx [%s]", sx_name);
721 if (sx_pdata.saw_recurrence)
722 g_warning(
"saw recurrence in supposedly version 1 sx [%s]", sx_name);
725 if (strcmp((
const char *)attr_value,
726 schedxaction_version2_string) == 0)
728 if (sx_pdata.saw_freqspec)
729 g_warning(
"saw freqspec in version 2 sx [%s]", sx_name);
730 if (!sx_pdata.saw_recurrence)
731 g_critical(
"did not find recurrence in version 2 sx [%s]", sx_name);
737 gdata->cb( tag, gdata->parsedata, sx );
740 if ( sx->template_acct == NULL )
748 book = sixdata->book;
758 g_warning(
"Error getting template root account from being-parsed Book." );
765 g_warning(
"no template account with name [%s]", guidstr);
769 g_debug(
"template account name [%s] for SX with GncGUID [%s]",
778 sx->template_acct = acct;
788 gnc_schedXaction_sixtp_parser_create(
void)
790 return sixtp_dom_parser_new( gnc_schedXaction_end_handler, NULL, NULL );
795 tt_act_handler( xmlNodePtr node, gpointer data )
801 acc = dom_tree_to_account(node, txd->book);
820 com = gnc_commodity_table_lookup( table,
821 "template",
"template" );
831 "template",
"template",
832 "template",
"template",
838 txd->accts = g_list_append( txd->accts, acc );
846 tt_trn_handler( xmlNodePtr node, gpointer data )
851 trn = dom_tree_to_transaction( node, txd->book );
859 txd->transactions = g_list_append( txd->transactions, trn );
867 { GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 },
868 { GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 },
869 { NULL, NULL, 0, 0 },
873 gnc_template_transaction_end_handler(gpointer data_for_children,
874 GSList* data_from_children,
875 GSList* sibling_data,
876 gpointer parent_data,
877 gpointer global_data,
881 gboolean successful = FALSE;
882 xmlNodePtr tree = data_for_children;
884 QofBook *book = gdata->bookdata;
890 txd.transactions = NULL;
910 g_return_val_if_fail( tree, FALSE );
912 successful = dom_tree_generic_parse( tree, tt_dom_handlers, &txd );
916 gdata->cb( tag, gdata->parsedata, &txd );
920 g_warning(
"failed to parse template transaction");
921 xmlElemDump( stdout, NULL, tree );
925 for ( n = txd.accts; n; n = n->next )
929 for ( n = txd.transactions; n; n = n->next )
933 g_list_free( txd.accts );
934 g_list_free( txd.transactions );
942 gnc_template_transaction_sixtp_parser_create(
void )
944 return sixtp_dom_parser_new( gnc_template_transaction_end_handler,
const GDate * xaccSchedXactionGetEndDate(const SchedXaction *sx)
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
GList * gnc_sx_get_schedule(const SchedXaction *sx)
#define xaccSchedXactionGetSlots(X)
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
Account * gnc_book_get_template_root(const QofBook *book)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
#define xaccAccountGetGUID(X)
api for GnuCash version 2 XML-based file format
#define GUID_ENCODING_LENGTH
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
#define xaccSchedXactionGetGUID(X)
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
void xaccAccountBeginEdit(Account *acc)
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
const char * xaccAccountGetName(const Account *acc)
gboolean xaccSchedXactionHasOccurDef(const SchedXaction *sx)
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
void xaccSchedXactionDestroy(SchedXaction *sx)
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
GList * gnc_sx_get_defer_instances(SchedXaction *sx)
Returns the defer list from the SX.
gint gnc_sx_get_instance_count(const SchedXaction *sx, SXTmpStateData *stateData)
Get the instance count.