30 #include "gnc-xml-helper.h" 32 #include "sixtp-utils.h" 33 #include "sixtp-parsers.h" 34 #include "sixtp-utils.h" 35 #include "sixtp-dom-parsers.h" 36 #include "sixtp-dom-generators.h" 41 #include "io-gncxml-gen.h" 43 #include "sixtp-dom-parsers.h" 46 #define G_LOG_DOMAIN "gnc.backend.file.sx" 50 #define SX_NAME "sx:name" 51 #define SX_ENABLED "sx:enabled" 52 #define SX_AUTOCREATE "sx:autoCreate" 53 #define SX_AUTOCREATE_NOTIFY "sx:autoCreateNotify" 54 #define SX_ADVANCE_CREATE_DAYS "sx:advanceCreateDays" 55 #define SX_ADVANCE_REMIND_DAYS "sx:advanceRemindDays" 56 #define SX_INSTANCE_COUNT "sx:instanceCount" 57 #define SX_START "sx:start" 58 #define SX_LAST "sx:last" 59 #define SX_NUM_OCCUR "sx:num-occur" 60 #define SX_REM_OCCUR "sx:rem-occur" 61 #define SX_END "sx:end" 62 #define SX_TEMPL_ACCT "sx:templ-acct" 63 #define SX_FREQSPEC "sx:freqspec" 64 #define SX_SCHEDULE "sx:schedule" 65 #define SX_SLOTS "sx:slots" 66 #define SX_DEFER_INSTANCE "sx:deferredInstance" 72 #define GNC_ACCOUNT_TAG "gnc:account" 73 #define GNC_TRANSACTION_TAG "gnc:transaction" 74 #define GNC_SCHEDXACTION_TAG "gnc:schedxaction" 76 const gchar* schedxaction_version_string =
"1.0.0";
77 const gchar* schedxaction_version2_string =
"2.0.0";
80 gnc_schedXaction_dom_tree_create (SchedXaction* sx)
86 gboolean allow_2_2_incompat = TRUE;
87 gchar* name = g_strdup (xaccSchedXactionGetName (sx));
92 ret = xmlNewNode (NULL, BAD_CAST GNC_SCHEDXACTION_TAG);
94 if (allow_2_2_incompat)
95 xmlSetProp (ret, BAD_CAST
"version", BAD_CAST schedxaction_version2_string);
97 xmlSetProp (ret, BAD_CAST
"version", BAD_CAST schedxaction_version_string);
100 guid_to_dom_tree (SX_ID,
103 xmlNewTextChild (ret, NULL, BAD_CAST SX_NAME, checked_char_cast (name));
106 if (allow_2_2_incompat)
108 xmlNewTextChild (ret, NULL, BAD_CAST SX_ENABLED,
109 BAD_CAST (sx->enabled ?
"y" :
"n"));
112 xmlNewTextChild (ret, NULL, BAD_CAST SX_AUTOCREATE,
113 BAD_CAST (sx->autoCreateOption ?
"y" :
"n"));
114 xmlNewTextChild (ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY,
115 BAD_CAST (sx->autoCreateNotify ?
"y" :
"n"));
116 xmlAddChild (ret, int_to_dom_tree (SX_ADVANCE_CREATE_DAYS,
117 sx->advanceCreateDays));
118 xmlAddChild (ret, int_to_dom_tree (SX_ADVANCE_REMIND_DAYS,
119 sx->advanceRemindDays));
122 xmlAddChild (ret, int_to_dom_tree (SX_INSTANCE_COUNT,
126 gdate_to_dom_tree (SX_START,
127 xaccSchedXactionGetStartDate (sx)));
129 date = xaccSchedXactionGetLastOccurDate (sx);
130 if (g_date_valid (date))
132 xmlAddChild (ret, gdate_to_dom_tree (SX_LAST, date));
138 xmlAddChild (ret, int_to_dom_tree (SX_NUM_OCCUR,
139 xaccSchedXactionGetNumOccur (sx)));
140 xmlAddChild (ret, int_to_dom_tree (SX_REM_OCCUR,
141 xaccSchedXactionGetRemOccur (sx)));
144 else if (xaccSchedXactionHasEndDate (sx))
147 gdate_to_dom_tree (SX_END,
153 guid_to_dom_tree (SX_TEMPL_ACCT,
156 if (allow_2_2_incompat)
158 xmlNodePtr schedule_node = xmlNewNode (NULL,
159 BAD_CAST
"sx:schedule");
161 for (; schedule != NULL; schedule = schedule->next)
163 xmlAddChild (schedule_node, recurrence_to_dom_tree (
"gnc:recurrence",
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);
194 xmlAddChild (ret, qof_instance_slots_to_dom_tree (SX_SLOTS,
203 gboolean saw_freqspec;
204 gboolean saw_recurrence;
209 sx_id_handler (xmlNodePtr node, gpointer
sx_pdata)
212 SchedXaction* sx = pdata->sx;
213 GncGUID* tmp = dom_tree_to_guid (node);
215 g_return_val_if_fail (tmp, FALSE);
216 xaccSchedXactionSetGUID (sx, tmp);
224 sx_name_handler (xmlNodePtr node, gpointer
sx_pdata)
227 SchedXaction* sx = pdata->sx;
228 gchar* tmp = dom_tree_to_text (node);
229 DEBUG (
"sx named [%s]", tmp);
230 g_return_val_if_fail (tmp, FALSE);
237 sx_enabled_handler (xmlNodePtr node, gpointer
sx_pdata)
240 SchedXaction* sx = pdata->sx;
241 gchar* tmp = dom_tree_to_text (node);
243 sx->enabled = (g_strcmp0 (tmp,
"y") == 0 ? TRUE : FALSE);
250 sx_autoCreate_handler (xmlNodePtr node, gpointer
sx_pdata)
253 SchedXaction* sx = pdata->sx;
254 gchar* tmp = dom_tree_to_text (node);
256 sx->autoCreateOption = (g_strcmp0 (tmp,
"y") == 0 ? TRUE : FALSE);
263 sx_notify_handler (xmlNodePtr node, gpointer
sx_pdata)
266 SchedXaction* sx = pdata->sx;
267 gchar* tmp = dom_tree_to_text (node);
269 sx->autoCreateNotify = (g_strcmp0 (tmp,
"y") == 0 ? TRUE : FALSE);
276 sx_advCreate_handler (xmlNodePtr node, gpointer
sx_pdata)
279 SchedXaction* sx = pdata->sx;
282 if (! dom_tree_to_integer (node, &advCreate))
287 xaccSchedXactionSetAdvanceCreation (sx, advCreate);
292 sx_advRemind_handler (xmlNodePtr node, gpointer
sx_pdata)
295 SchedXaction* sx = pdata->sx;
298 if (! dom_tree_to_integer (node, &advRemind))
303 xaccSchedXactionSetAdvanceReminder (sx, advRemind);
309 sx_set_date (xmlNodePtr node, SchedXaction* sx,
310 void (*settor) (SchedXaction* sx,
const GDate* d))
313 date = dom_tree_to_gdate (node);
314 g_return_val_if_fail (date, FALSE);
315 (*settor) (sx, date);
323 sx_instcount_handler (xmlNodePtr node, gpointer
sx_pdata)
326 SchedXaction* sx = pdata->sx;
329 if (! dom_tree_to_integer (node, &instanceNum))
340 sx_start_handler (xmlNodePtr node, gpointer
sx_pdata)
343 SchedXaction* sx = pdata->sx;
345 return sx_set_date (node, sx, xaccSchedXactionSetStartDate);
350 sx_last_handler (xmlNodePtr node, gpointer
sx_pdata)
353 SchedXaction* sx = pdata->sx;
355 return sx_set_date (node, sx, xaccSchedXactionSetLastOccurDate);
360 sx_end_handler (xmlNodePtr node, gpointer
sx_pdata)
363 SchedXaction* sx = pdata->sx;
369 _fixup_recurrence_start_dates (
const GDate* sx_start_date, GList* schedule)
372 for (iter = schedule; iter != NULL; iter = iter->next)
379 start = *sx_start_date;
380 g_date_subtract_days (&start, 1);
382 g_date_clear (&next, 1);
384 recurrenceNextInstance (r, &start, &next);
385 g_return_if_fail (g_date_valid (&next));
391 g_date_strftime (date_str, 127,
"%x", &next);
392 sched_str = recurrenceToString (r);
393 DEBUG (
"setting recurrence [%s] start date to [%s]",
394 sched_str, date_str);
399 recurrenceGetMultiplier (r),
400 recurrenceGetPeriodType (r),
402 recurrenceGetWeekendAdjust (r));
405 if (g_list_length (schedule) == 1
406 && recurrenceGetPeriodType ((
Recurrence*)g_list_nth_data (schedule,
411 g_date_strftime (date_buf, 127,
"%x", sx_start_date);
412 recurrenceSet (fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE);
413 DEBUG (
"fixed up period=ONCE Recurrence to date [%s]", date_buf);
418 sx_freqspec_handler (xmlNodePtr node, gpointer
sx_pdata)
421 SchedXaction* sx = pdata->sx;
425 g_return_val_if_fail (node, FALSE);
427 schedule = dom_tree_freqSpec_to_recurrences (node, pdata->book);
429 debug_str = recurrenceListToString (schedule);
430 DEBUG (
"parsed from freqspec [%s]", debug_str);
433 _fixup_recurrence_start_dates (xaccSchedXactionGetStartDate (sx), schedule);
434 pdata->saw_freqspec = TRUE;
440 sx_schedule_recurrence_handler (xmlNodePtr node, gpointer parsing_data)
442 GList** schedule = (GList**)parsing_data;
444 Recurrence* r = dom_tree_to_recurrence (node);
445 g_return_val_if_fail (r, FALSE);
446 sched_str = recurrenceToString (r);
447 DEBUG (
"parsed recurrence [%s]", sched_str);
449 *schedule = g_list_append (*schedule, r);
455 {
"gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 },
460 sx_recurrence_handler (xmlNodePtr node, gpointer _pdata)
462 struct sx_pdata* parsing_data =
static_cast<decltype (parsing_data)
> (_pdata);
463 GList* schedule = NULL;
466 g_return_val_if_fail (node, FALSE);
468 if (!dom_tree_generic_parse (node, sx_recurrence_list_handlers, &schedule))
471 debug_str = recurrenceListToString (schedule);
472 DEBUG (
"setting freshly-parsed schedule: [%s]", debug_str);
475 parsing_data->saw_recurrence = TRUE;
481 sx_defer_last_handler (xmlNodePtr node, gpointer gpTSD)
486 g_return_val_if_fail (node, FALSE);
487 gd = dom_tree_to_gdate (node);
488 g_return_val_if_fail (gd, FALSE);
489 tsd->last_date = *gd;
496 sx_defer_rem_occur_handler (xmlNodePtr node, gpointer gpTSD)
500 g_return_val_if_fail (node, FALSE);
502 if (! dom_tree_to_integer (node, &remOccur))
506 tsd->num_occur_rem = remOccur;
512 sx_defer_inst_count_handler (xmlNodePtr node, gpointer gpTSD)
516 g_return_val_if_fail (node, FALSE);
518 if (! dom_tree_to_integer (node, &instCount))
522 tsd->num_inst = instCount;
529 { SX_LAST, sx_defer_last_handler, 1, 0 },
530 { SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 },
531 { SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 },
537 sx_defer_inst_handler (xmlNodePtr node, gpointer
sx_pdata)
540 SchedXaction* sx = pdata->sx;
543 g_return_val_if_fail (node, FALSE);
546 g_assert (sx_defer_dom_handlers != NULL);
547 if (!dom_tree_generic_parse (node,
548 sx_defer_dom_handlers,
551 xmlElemDump (stdout, NULL, node);
558 sx->deferredList = g_list_append (sx->deferredList, tsd);
564 sx_numOccur_handler (xmlNodePtr node, gpointer
sx_pdata)
567 SchedXaction* sx = pdata->sx;
570 if (! dom_tree_to_integer (node, &numOccur))
583 sx_templ_acct_handler (xmlNodePtr node, gpointer
sx_pdata)
586 SchedXaction* sx = pdata->sx;
587 GncGUID* templ_acct_guid = dom_tree_to_guid (node);
590 if (!templ_acct_guid)
596 sx_set_template_account (sx, account);
597 guid_free (templ_acct_guid);
605 sx_remOccur_handler (xmlNodePtr node, gpointer
sx_pdata)
608 SchedXaction* sx = pdata->sx;
611 if (! dom_tree_to_integer (node, &remOccur))
616 xaccSchedXactionSetRemOccur (sx, remOccur);
623 sx_slots_handler (xmlNodePtr node, gpointer
sx_pdata)
626 SchedXaction* sx = pdata->sx;
628 return dom_tree_create_instance_slots (node, QOF_INSTANCE (sx));
633 { SX_ID, sx_id_handler, 1, 0 },
634 { SX_NAME, sx_name_handler, 1, 0 },
635 { SX_ENABLED, sx_enabled_handler, 0, 0 },
636 { SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 },
637 { SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
638 { SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
639 { SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
640 { SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
641 { SX_START, sx_start_handler, 1, 0 },
642 { SX_LAST, sx_last_handler, 0, 0 },
643 { SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },
644 { SX_REM_OCCUR, sx_remOccur_handler, 0, 0 },
645 { SX_END, sx_end_handler, 0, 0 },
646 { SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 },
647 { SX_FREQSPEC, sx_freqspec_handler, 0, 0 },
648 { SX_SCHEDULE, sx_recurrence_handler, 0, 0 },
649 { SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 },
650 { SX_SLOTS, sx_slots_handler, 0, 0 },
655 gnc_schedXaction_end_handler (gpointer data_for_children,
656 GSList* data_from_children, GSList* sibling_data,
657 gpointer parent_data, gpointer global_data,
658 gpointer* result,
const gchar* tag)
661 gboolean successful = FALSE;
662 xmlNodePtr tree = (xmlNodePtr)data_for_children;
663 gxpf_data* gdata = (gxpf_data*)global_data;
676 g_return_val_if_fail (tree, FALSE);
684 g_assert (sx_dom_handlers != NULL);
686 successful = dom_tree_generic_parse (tree, sx_dom_handlers, &
sx_pdata);
689 g_critical (
"failed to parse scheduled xaction");
690 xmlElemDump (stdout, NULL, tree);
691 gnc_sx_begin_edit (sx);
696 if (tree->properties)
698 gchar* sx_name = xaccSchedXactionGetName (sx);
700 for (attr = tree->properties; attr != NULL; attr = attr->next)
702 xmlChar* attr_value = attr->children->content;
703 DEBUG (
"sx attribute name[%s] value[%s]", attr->name, attr_value);
704 if (strcmp ((
const char*)attr->name,
"version") != 0)
706 g_warning (
"unknown sx attribute [%s]", attr->name);
712 if (strcmp ((
const char*)attr_value,
713 schedxaction_version_string) == 0)
716 g_critical (
"did not see freqspec in version 1 sx [%s]", sx_name);
718 g_warning (
"saw recurrence in supposedly version 1 sx [%s]", sx_name);
721 if (strcmp ((
const char*)attr_value,
722 schedxaction_version2_string) == 0)
725 g_warning (
"saw freqspec in version 2 sx [%s]", sx_name);
727 g_critical (
"did not find recurrence in version 2 sx [%s]", sx_name);
733 gdata->cb (tag, gdata->parsedata, sx);
736 if (sx->template_acct == NULL)
740 sixtp_gdv2* sixdata =
static_cast<decltype (sixdata)
> (gdata->parsedata);
744 book = sixdata->book;
754 g_warning (
"Error getting template root account from being-parsed Book.");
761 g_warning (
"no template account with name [%s]", guidstr);
765 DEBUG (
"template account name [%s] for SX with GncGUID [%s]",
774 sx->template_acct = acct;
784 gnc_schedXaction_sixtp_parser_create (
void)
786 return sixtp_dom_parser_new (gnc_schedXaction_end_handler, NULL, NULL);
791 tt_act_handler (xmlNodePtr node, gpointer data)
793 gnc_template_xaction_data* txd =
static_cast<decltype (txd)
> (data);
797 acc = dom_tree_to_account (node, txd->book);
813 gnc_commodity_table*
table;
816 com = gnc_commodity_table_lookup (
table,
817 GNC_COMMODITY_NS_TEMPLATE,
"template");
827 "template", GNC_COMMODITY_NS_TEMPLATE,
828 "template",
"template",
834 txd->accts = g_list_append (txd->accts, acc);
842 tt_trn_handler (xmlNodePtr node, gpointer data)
844 gnc_template_xaction_data* txd =
static_cast<decltype (txd)
> (data);
847 trn = dom_tree_to_transaction (node, txd->book);
855 txd->transactions = g_list_append (txd->transactions, trn);
863 { GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 },
864 { GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 },
865 { NULL, NULL, 0, 0 },
869 gnc_template_transaction_end_handler (gpointer data_for_children,
870 GSList* data_from_children,
871 GSList* sibling_data,
872 gpointer parent_data,
873 gpointer global_data,
877 gboolean successful = FALSE;
878 xmlNodePtr tree =
static_cast<decltype (tree)
> (data_for_children);
879 gxpf_data* gdata =
static_cast<decltype (gdata)
> (global_data);
880 QofBook* book =
static_cast<decltype (book)
> (gdata->bookdata);
882 gnc_template_xaction_data txd;
886 txd.transactions = NULL;
906 g_return_val_if_fail (tree, FALSE);
908 successful = dom_tree_generic_parse (tree, tt_dom_handlers, &txd);
912 gdata->cb (tag, gdata->parsedata, &txd);
916 g_warning (
"failed to parse template transaction");
917 xmlElemDump (stdout, NULL, tree);
921 for (n = txd.accts; n; n = n->next)
925 for (n = txd.transactions; n; n = n->next)
929 g_list_free (txd.accts);
930 g_list_free (txd.transactions);
938 gnc_template_transaction_sixtp_parser_create (
void)
940 return sixtp_dom_parser_new (gnc_template_transaction_end_handler,
const GDate * xaccSchedXactionGetEndDate(const SchedXaction *sx)
Returns invalid date when there is no end-date specified.
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
Sets the instance count to something other than the default.
GList * gnc_sx_get_schedule(const SchedXaction *sx)
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
Set to '0' to turn off number-of-occurrences definition.
#define DEBUG(format, args...)
Print a debugging message.
Account * gnc_book_get_template_root(const QofBook *book)
Returns the template group from the book.
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Just the variable temporal bits from the SX structure.
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
The gnc_account_lookup_by_name() subroutine fetches the account by name from the descendants of the s...
#define xaccAccountGetGUID(X)
api for GnuCash version 2 XML-based file format
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
Create a new commodity.
Anchor Scheduled Transaction info in a book.
#define xaccSchedXactionGetGUID(X)
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
A copy of the name is made.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Creates and initializes a scheduled transaction.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
gboolean xaccSchedXactionHasOccurDef(const SchedXaction *sx)
Returns true if the scheduled transaction has a defined number of occurrences, false if not...
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
Set to an invalid GDate to turn off 'end-date' definition.
The type used to store guids in C.
void xaccSchedXactionDestroy(SchedXaction *sx)
Cleans up and frees a SchedXaction and its associated data.
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account's commodity.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
GList * gnc_sx_get_defer_instances(SchedXaction *sx)
Returns the defer list from the SX; this is a (date-)sorted temporal-state-data instance list...
gint gnc_sx_get_instance_count(const SchedXaction *sx, SXTmpStateData *stateData)
Get the instance count.