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 auto tmp = dom_tree_to_guid (node);
215 g_return_val_if_fail (tmp, FALSE);
216 xaccSchedXactionSetGUID (sx, &*tmp);
223 sx_name_handler (xmlNodePtr node, gpointer
sx_pdata)
230 sx_enabled_handler (xmlNodePtr node, gpointer
sx_pdata)
233 auto set_enabled = [](SchedXaction* sx,
const char* txt)
235 sx->enabled = !g_strcmp0 (txt,
"y");
237 return apply_xmlnode_text (set_enabled, pdata->sx, node);
241 sx_autoCreate_handler (xmlNodePtr node, gpointer
sx_pdata)
244 auto set_autocreate = [](SchedXaction* sx,
const char* txt)
246 sx->autoCreateOption = !g_strcmp0 (txt,
"y");
248 return apply_xmlnode_text (set_autocreate, pdata->sx, node);
252 sx_notify_handler (xmlNodePtr node, gpointer
sx_pdata)
255 auto set_notify = [](SchedXaction* sx,
const char* txt)
257 sx->autoCreateNotify = !g_strcmp0 (txt,
"y");
259 return apply_xmlnode_text (set_notify, pdata->sx, node);
263 sx_advCreate_handler (xmlNodePtr node, gpointer
sx_pdata)
266 SchedXaction* sx = pdata->sx;
269 if (! dom_tree_to_integer (node, &advCreate))
274 xaccSchedXactionSetAdvanceCreation (sx, advCreate);
279 sx_advRemind_handler (xmlNodePtr node, gpointer
sx_pdata)
282 SchedXaction* sx = pdata->sx;
285 if (! dom_tree_to_integer (node, &advRemind))
290 xaccSchedXactionSetAdvanceReminder (sx, advRemind);
296 sx_set_date (xmlNodePtr node, SchedXaction* sx,
297 void (*settor) (SchedXaction* sx,
const GDate* d))
300 date = dom_tree_to_gdate (node);
301 g_return_val_if_fail (date, FALSE);
302 (*settor) (sx, date);
310 sx_instcount_handler (xmlNodePtr node, gpointer
sx_pdata)
313 SchedXaction* sx = pdata->sx;
316 if (! dom_tree_to_integer (node, &instanceNum))
327 sx_start_handler (xmlNodePtr node, gpointer
sx_pdata)
330 SchedXaction* sx = pdata->sx;
332 return sx_set_date (node, sx, xaccSchedXactionSetStartDate);
337 sx_last_handler (xmlNodePtr node, gpointer
sx_pdata)
340 SchedXaction* sx = pdata->sx;
342 return sx_set_date (node, sx, xaccSchedXactionSetLastOccurDate);
347 sx_end_handler (xmlNodePtr node, gpointer
sx_pdata)
350 SchedXaction* sx = pdata->sx;
356 _fixup_recurrence_start_dates (
const GDate* sx_start_date, GList* schedule)
359 for (iter = schedule; iter != NULL; iter = iter->next)
366 start = *sx_start_date;
367 g_date_subtract_days (&start, 1);
369 g_date_clear (&next, 1);
371 recurrenceNextInstance (r, &start, &next);
372 g_return_if_fail (g_date_valid (&next));
378 g_date_strftime (date_str, 127,
"%x", &next);
379 sched_str = recurrenceToString (r);
380 DEBUG (
"setting recurrence [%s] start date to [%s]",
381 sched_str, date_str);
386 recurrenceGetMultiplier (r),
387 recurrenceGetPeriodType (r),
389 recurrenceGetWeekendAdjust (r));
392 if (g_list_length (schedule) == 1
393 && recurrenceGetPeriodType ((
Recurrence*)g_list_nth_data (schedule,
398 g_date_strftime (date_buf, 127,
"%x", sx_start_date);
399 recurrenceSet (fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE);
400 DEBUG (
"fixed up period=ONCE Recurrence to date [%s]", date_buf);
405 sx_freqspec_handler (xmlNodePtr node, gpointer
sx_pdata)
408 SchedXaction* sx = pdata->sx;
412 g_return_val_if_fail (node, FALSE);
414 schedule = dom_tree_freqSpec_to_recurrences (node, pdata->book);
416 debug_str = recurrenceListToString (schedule);
417 DEBUG (
"parsed from freqspec [%s]", debug_str);
420 _fixup_recurrence_start_dates (xaccSchedXactionGetStartDate (sx), schedule);
421 pdata->saw_freqspec = TRUE;
427 sx_schedule_recurrence_handler (xmlNodePtr node, gpointer parsing_data)
429 GList** schedule = (GList**)parsing_data;
431 Recurrence* r = dom_tree_to_recurrence (node);
432 g_return_val_if_fail (r, FALSE);
433 sched_str = recurrenceToString (r);
434 DEBUG (
"parsed recurrence [%s]", sched_str);
436 *schedule = g_list_append (*schedule, r);
442 {
"gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 },
447 sx_recurrence_handler (xmlNodePtr node, gpointer _pdata)
449 struct sx_pdata* parsing_data =
static_cast<decltype (parsing_data)
> (_pdata);
450 GList* schedule = NULL;
453 g_return_val_if_fail (node, FALSE);
455 if (!dom_tree_generic_parse (node, sx_recurrence_list_handlers, &schedule))
458 debug_str = recurrenceListToString (schedule);
459 DEBUG (
"setting freshly-parsed schedule: [%s]", debug_str);
462 parsing_data->saw_recurrence = TRUE;
468 sx_defer_last_handler (xmlNodePtr node, gpointer gpTSD)
473 g_return_val_if_fail (node, FALSE);
474 gd = dom_tree_to_gdate (node);
475 g_return_val_if_fail (gd, FALSE);
476 tsd->last_date = *gd;
483 sx_defer_rem_occur_handler (xmlNodePtr node, gpointer gpTSD)
487 g_return_val_if_fail (node, FALSE);
489 if (! dom_tree_to_integer (node, &remOccur))
493 tsd->num_occur_rem = remOccur;
499 sx_defer_inst_count_handler (xmlNodePtr node, gpointer gpTSD)
503 g_return_val_if_fail (node, FALSE);
505 if (! dom_tree_to_integer (node, &instCount))
509 tsd->num_inst = instCount;
516 { SX_LAST, sx_defer_last_handler, 1, 0 },
517 { SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 },
518 { SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 },
524 sx_defer_inst_handler (xmlNodePtr node, gpointer
sx_pdata)
527 SchedXaction* sx = pdata->sx;
530 g_return_val_if_fail (node, FALSE);
533 g_assert (sx_defer_dom_handlers != NULL);
534 if (!dom_tree_generic_parse (node,
535 sx_defer_dom_handlers,
538 xmlElemDump (stdout, NULL, node);
545 sx->deferredList = g_list_append (sx->deferredList, tsd);
551 sx_numOccur_handler (xmlNodePtr node, gpointer
sx_pdata)
554 SchedXaction* sx = pdata->sx;
557 if (! dom_tree_to_integer (node, &numOccur))
570 sx_templ_acct_handler (xmlNodePtr node, gpointer
sx_pdata)
573 SchedXaction* sx = pdata->sx;
574 auto templ_acct_guid = dom_tree_to_guid (node);
577 if (!templ_acct_guid)
583 sx_set_template_account (sx, account);
591 sx_remOccur_handler (xmlNodePtr node, gpointer
sx_pdata)
594 SchedXaction* sx = pdata->sx;
597 if (! dom_tree_to_integer (node, &remOccur))
602 xaccSchedXactionSetRemOccur (sx, remOccur);
609 sx_slots_handler (xmlNodePtr node, gpointer
sx_pdata)
612 SchedXaction* sx = pdata->sx;
614 return dom_tree_create_instance_slots (node, QOF_INSTANCE (sx));
619 { SX_ID, sx_id_handler, 1, 0 },
620 { SX_NAME, sx_name_handler, 1, 0 },
621 { SX_ENABLED, sx_enabled_handler, 0, 0 },
622 { SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 },
623 { SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
624 { SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
625 { SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
626 { SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
627 { SX_START, sx_start_handler, 1, 0 },
628 { SX_LAST, sx_last_handler, 0, 0 },
629 { SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },
630 { SX_REM_OCCUR, sx_remOccur_handler, 0, 0 },
631 { SX_END, sx_end_handler, 0, 0 },
632 { SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 },
633 { SX_FREQSPEC, sx_freqspec_handler, 0, 0 },
634 { SX_SCHEDULE, sx_recurrence_handler, 0, 0 },
635 { SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 },
636 { SX_SLOTS, sx_slots_handler, 0, 0 },
641 gnc_schedXaction_end_handler (gpointer data_for_children,
642 GSList* data_from_children, GSList* sibling_data,
643 gpointer parent_data, gpointer global_data,
644 gpointer* result,
const gchar* tag)
647 gboolean successful = FALSE;
648 xmlNodePtr tree = (xmlNodePtr)data_for_children;
649 gxpf_data* gdata = (gxpf_data*)global_data;
662 g_return_val_if_fail (tree, FALSE);
670 g_assert (sx_dom_handlers != NULL);
672 successful = dom_tree_generic_parse (tree, sx_dom_handlers, &
sx_pdata);
675 g_critical (
"failed to parse scheduled xaction");
676 xmlElemDump (stdout, NULL, tree);
677 gnc_sx_begin_edit (sx);
682 if (tree->properties)
684 gchar* sx_name = xaccSchedXactionGetName (sx);
686 for (attr = tree->properties; attr != NULL; attr = attr->next)
688 xmlChar* attr_value = attr->children->content;
689 DEBUG (
"sx attribute name[%s] value[%s]", attr->name, attr_value);
690 if (strcmp ((
const char*)attr->name,
"version") != 0)
692 g_warning (
"unknown sx attribute [%s]", attr->name);
698 if (strcmp ((
const char*)attr_value,
699 schedxaction_version_string) == 0)
702 g_critical (
"did not see freqspec in version 1 sx [%s]", sx_name);
704 g_warning (
"saw recurrence in supposedly version 1 sx [%s]", sx_name);
707 if (strcmp ((
const char*)attr_value,
708 schedxaction_version2_string) == 0)
711 g_warning (
"saw freqspec in version 2 sx [%s]", sx_name);
713 g_critical (
"did not find recurrence in version 2 sx [%s]", sx_name);
719 gdata->cb (tag, gdata->parsedata, sx);
722 if (sx->template_acct == NULL)
726 sixtp_gdv2* sixdata =
static_cast<decltype (sixdata)
> (gdata->parsedata);
730 book = sixdata->book;
740 g_warning (
"Error getting template root account from being-parsed Book.");
747 g_warning (
"no template account with name [%s]", guidstr);
751 DEBUG (
"template account name [%s] for SX with GncGUID [%s]",
760 sx->template_acct = acct;
770 gnc_schedXaction_sixtp_parser_create (
void)
772 return sixtp_dom_parser_new (gnc_schedXaction_end_handler, NULL, NULL);
777 tt_act_handler (xmlNodePtr node, gpointer data)
779 gnc_template_xaction_data* txd =
static_cast<decltype (txd)
> (data);
783 acc = dom_tree_to_account (node, txd->book);
799 gnc_commodity_table*
table;
802 com = gnc_commodity_table_lookup (
table,
803 GNC_COMMODITY_NS_TEMPLATE,
"template");
813 "template", GNC_COMMODITY_NS_TEMPLATE,
814 "template",
"template",
820 txd->accts = g_list_append (txd->accts, acc);
828 tt_trn_handler (xmlNodePtr node, gpointer data)
830 gnc_template_xaction_data* txd =
static_cast<decltype (txd)
> (data);
833 trn = dom_tree_to_transaction (node, txd->book);
841 txd->transactions = g_list_append (txd->transactions, trn);
849 { GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 },
850 { GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 },
851 { NULL, NULL, 0, 0 },
855 gnc_template_transaction_end_handler (gpointer data_for_children,
856 GSList* data_from_children,
857 GSList* sibling_data,
858 gpointer parent_data,
859 gpointer global_data,
863 gboolean successful = FALSE;
864 xmlNodePtr tree =
static_cast<decltype (tree)
> (data_for_children);
865 gxpf_data* gdata =
static_cast<decltype (gdata)
> (global_data);
866 QofBook* book =
static_cast<decltype (book)
> (gdata->bookdata);
868 gnc_template_xaction_data txd;
872 txd.transactions = NULL;
892 g_return_val_if_fail (tree, FALSE);
894 successful = dom_tree_generic_parse (tree, tt_dom_handlers, &txd);
898 gdata->cb (tag, gdata->parsedata, &txd);
902 g_warning (
"failed to parse template transaction");
903 xmlElemDump (stdout, NULL, tree);
907 for (n = txd.accts; n; n = n->next)
911 for (n = txd.transactions; n; n = n->next)
915 g_list_free (txd.accts);
916 g_list_free (txd.transactions);
924 gnc_template_transaction_sixtp_parser_create (
void)
926 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.