GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
SchedXaction.c
1 /********************************************************************\
2  * SchedXaction.c -- Scheduled Transaction implementation. *
3  * Copyright (C) 2001,2007 Joshua Sled <[email protected]> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact: *
17  * *
18  * Free Software Foundation Voice: +1-617-542-5942 *
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20  * Boston, MA 02110-1301, USA [email protected] *
21  * *
22 \********************************************************************/
23 
24 #include "config.h"
25 
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <string.h>
29 
30 #include "qof.h"
31 
32 #include "Account.h"
33 #include "SX-book.h"
34 #include "SX-ttinfo.h"
35 #include "SchedXaction.h"
36 #include "Transaction.h"
37 #include "gnc-engine.h"
38 #include "engine-helpers.h"
39 #include "qofinstance-p.h"
40 
41 #undef G_LOG_DOMAIN
42 #define G_LOG_DOMAIN "gnc.engine.sx"
43 
44 enum
45 {
46  PROP_0,
47  PROP_NAME, /* Table */
48  PROP_ENABLED, /* Table */
49  PROP_START_DATE, /* Table */
50  PROP_END_DATE, /* Table */
51  PROP_LAST_OCCURANCE_DATE, /* Table */
52  PROP_NUM_OCCURANCE, /* Table */
53  PROP_REM_OCCURANCE, /* Table */
54  PROP_AUTO_CREATE, /* Table */
55  PROP_AUTO_CREATE_NOTIFY, /* Table */
56  PROP_ADVANCE_CREATION_DAYS, /* Table */
57  PROP_ADVANCE_REMINDER_DAYS, /* Table */
58  PROP_INSTANCE_COUNT, /* Table */
59  PROP_TEMPLATE_ACCOUNT /* Table */
60 };
61 
62 /* GObject initialization */
63 G_DEFINE_TYPE(SchedXaction, gnc_schedxaction, QOF_TYPE_INSTANCE);
64 
65 static void
66 gnc_schedxaction_init(SchedXaction* sx)
67 {
68  sx->schedule = NULL;
69 
70  g_date_clear( &sx->last_date, 1 );
71  g_date_clear( &sx->start_date, 1 );
72  g_date_clear( &sx->end_date, 1 );
73 
74  sx->enabled = 1;
75  sx->num_occurances_total = 0;
76  sx->autoCreateOption = FALSE;
77  sx->autoCreateNotify = FALSE;
78  sx->advanceCreateDays = 0;
79  sx->advanceRemindDays = 0;
80  sx->instance_num = 0;
81  sx->deferredList = NULL;
82 }
83 
84 static void
85 gnc_schedxaction_dispose(GObject *sxp)
86 {
87  G_OBJECT_CLASS(gnc_schedxaction_parent_class)->dispose(sxp);
88 }
89 
90 static void
91 gnc_schedxaction_finalize(GObject* sxp)
92 {
93  G_OBJECT_CLASS(gnc_schedxaction_parent_class)->finalize(sxp);
94 }
95 
96 /* Note that g_value_set_object() refs the object, as does
97  * g_object_get(). But g_object_get() only unrefs once when it disgorges
98  * the object, leaving an unbalanced ref, which leaks. So instead of
99  * using g_value_set_object(), use g_value_take_object() which doesn't
100  * ref the object when used in get_property().
101  */
102 static void
103 gnc_schedxaction_get_property (GObject *object,
104  guint prop_id,
105  GValue *value,
106  GParamSpec *pspec)
107 {
108  SchedXaction *sx;
109 
110  g_return_if_fail(GNC_IS_SCHEDXACTION(object));
111 
112  sx = GNC_SCHEDXACTION(object);
113  switch (prop_id)
114  {
115  case PROP_NAME:
116  g_value_set_string(value, sx->name);
117  break;
118  case PROP_ENABLED:
119  g_value_set_boolean(value, sx->enabled);
120  break;
121  case PROP_NUM_OCCURANCE:
122  g_value_set_int(value, sx->num_occurances_total);
123  break;
124  case PROP_REM_OCCURANCE:
125  g_value_set_int(value, sx->num_occurances_remain);
126  break;
127  case PROP_AUTO_CREATE:
128  g_value_set_boolean(value, sx->autoCreateOption);
129  break;
130  case PROP_AUTO_CREATE_NOTIFY:
131  g_value_set_boolean(value, sx->autoCreateNotify);
132  break;
133  case PROP_ADVANCE_CREATION_DAYS:
134  g_value_set_int(value, sx->advanceCreateDays);
135  break;
136  case PROP_ADVANCE_REMINDER_DAYS:
137  g_value_set_int(value, sx->advanceRemindDays);
138  break;
139  case PROP_START_DATE:
140  g_value_set_boxed(value, &sx->start_date);
141  break;
142  case PROP_END_DATE:
143  /* g_value_set_boxed raises a critical error if sx->end_date
144  * is invalid */
145  if (g_date_valid (&sx->end_date))
146  g_value_set_boxed(value, &sx->end_date);
147  break;
148  case PROP_LAST_OCCURANCE_DATE:
149  /* g_value_set_boxed raises a critical error if sx->last_date
150  * is invalid */
151  if (g_date_valid (&sx->last_date))
152  g_value_set_boxed(value, &sx->last_date);
153  break;
154  case PROP_INSTANCE_COUNT:
155  g_value_set_int(value, sx->instance_num);
156  break;
157  case PROP_TEMPLATE_ACCOUNT:
158  g_value_take_object(value, sx->template_acct);
159  break;
160  default:
161  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
162  break;
163  }
164 }
165 
166 static void
167 gnc_schedxaction_set_property (GObject *object,
168  guint prop_id,
169  const GValue *value,
170  GParamSpec *pspec)
171 {
172  SchedXaction *sx;
173 
174  g_return_if_fail(GNC_IS_SCHEDXACTION(object));
175 
176  sx = GNC_SCHEDXACTION(object);
177  g_assert (qof_instance_get_editlevel(sx));
178 
179  switch (prop_id)
180  {
181  case PROP_NAME:
182  xaccSchedXactionSetName(sx, g_value_get_string(value));
183  break;
184  case PROP_ENABLED:
185  xaccSchedXactionSetEnabled(sx, g_value_get_boolean(value));
186  break;
187  case PROP_NUM_OCCURANCE:
188  xaccSchedXactionSetNumOccur(sx, g_value_get_int(value));
189  break;
190  case PROP_REM_OCCURANCE:
191  xaccSchedXactionSetRemOccur(sx, g_value_get_int(value));
192  break;
193  case PROP_AUTO_CREATE:
194  xaccSchedXactionSetAutoCreate(sx, g_value_get_boolean(value), sx->autoCreateNotify);
195  break;
196  case PROP_AUTO_CREATE_NOTIFY:
197  xaccSchedXactionSetAutoCreate(sx, sx->autoCreateOption, g_value_get_boolean(value));
198  break;
199  case PROP_ADVANCE_CREATION_DAYS:
200  xaccSchedXactionSetAdvanceCreation(sx, g_value_get_int(value));
201  break;
202  case PROP_ADVANCE_REMINDER_DAYS:
203  xaccSchedXactionSetAdvanceReminder(sx, g_value_get_int(value));
204  break;
205  case PROP_START_DATE:
206  /* Note: when passed through a boxed gvalue, the julian value of the date is copied.
207  The date may appear invalid until a function requiring for dmy calculation is
208  called. */
209  xaccSchedXactionSetStartDate(sx, g_value_get_boxed(value));
210  break;
211  case PROP_END_DATE:
212  /* Note: when passed through a boxed gvalue, the julian value of the date is copied.
213  The date may appear invalid until a function requiring for dmy calculation is
214  called. */
215  xaccSchedXactionSetEndDate(sx, g_value_get_boxed(value));
216  break;
217  case PROP_LAST_OCCURANCE_DATE:
218  /* Note: when passed through a boxed gvalue, the julian value of the date is copied.
219  The date may appear invalid until a function requiring for dmy calculation is
220  called. */
221  xaccSchedXactionSetLastOccurDate(sx, g_value_get_boxed(value));
222  break;
223  case PROP_INSTANCE_COUNT:
224  gnc_sx_set_instance_count(sx, g_value_get_int(value));
225  break;
226  case PROP_TEMPLATE_ACCOUNT:
227  sx_set_template_account(sx, g_value_get_object(value));
228  break;
229  default:
230  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
231  break;
232  }
233 }
234 
235 static void
236 gnc_schedxaction_class_init (SchedXactionClass *klass)
237 {
238  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
239 
240  gobject_class->dispose = gnc_schedxaction_dispose;
241  gobject_class->finalize = gnc_schedxaction_finalize;
242  gobject_class->set_property = gnc_schedxaction_set_property;
243  gobject_class->get_property = gnc_schedxaction_get_property;
244 
245  g_object_class_install_property
246  (gobject_class,
247  PROP_NAME,
248  g_param_spec_string ("name",
249  "Scheduled Transaction Name",
250  "The name is an arbitrary string "
251  "assigned by the user. It is intended to "
252  "a short, 5 to 30 character long string "
253  "that is displayed by the GUI.",
254  NULL,
255  G_PARAM_READWRITE));
256 
257  g_object_class_install_property
258  (gobject_class,
259  PROP_ENABLED,
260  g_param_spec_boolean ("enabled",
261  "Enabled",
262  "TRUE if the scheduled transaction is enabled.",
263  TRUE,
264  G_PARAM_READWRITE));
265 
266  g_object_class_install_property
267  (gobject_class,
268  PROP_NUM_OCCURANCE,
269  g_param_spec_int ("num-occurance",
270  "Number of occurances",
271  "Total number of occurances for this scheduled transaction.",
272  0,
273  G_MAXINT16,
274  1,
275  G_PARAM_READWRITE));
276 
277  g_object_class_install_property
278  (gobject_class,
279  PROP_REM_OCCURANCE,
280  g_param_spec_int ("rem-occurance",
281  "Number of occurances remaining",
282  "Remaining number of occurances for this scheduled transaction.",
283  0,
284  G_MAXINT16,
285  1,
286  G_PARAM_READWRITE));
287 
288  g_object_class_install_property
289  (gobject_class,
290  PROP_AUTO_CREATE,
291  g_param_spec_boolean ("auto-create",
292  "Auto-create",
293  "TRUE if the transaction will be automatically "
294  "created when its time comes.",
295  FALSE,
296  G_PARAM_READWRITE));
297 
298  g_object_class_install_property
299  (gobject_class,
300  PROP_AUTO_CREATE_NOTIFY,
301  g_param_spec_boolean ("auto-create-notify",
302  "Auto-create-notify",
303  "TRUE if the the user will be notified when the transaction "
304  "is automatically created.",
305  FALSE,
306  G_PARAM_READWRITE));
307 
308  g_object_class_install_property
309  (gobject_class,
310  PROP_ADVANCE_CREATION_DAYS,
311  g_param_spec_int ("advance-creation-days",
312  "Days in advance to create",
313  "Number of days in advance to create this scheduled transaction.",
314  0,
315  G_MAXINT16,
316  0,
317  G_PARAM_READWRITE));
318 
319  g_object_class_install_property
320  (gobject_class,
321  PROP_ADVANCE_REMINDER_DAYS,
322  g_param_spec_int ("advance-reminder-days",
323  "Days in advance to remind",
324  "Number of days in advance to remind about this scheduled transaction.",
325  0,
326  G_MAXINT16,
327  0,
328  G_PARAM_READWRITE));
329 
330  g_object_class_install_property
331  (gobject_class,
332  PROP_START_DATE,
333  g_param_spec_boxed("start-date",
334  "Start Date",
335  "Date for the first occurence for the scheduled transaction.",
336  G_TYPE_DATE,
337  G_PARAM_READWRITE));
338 
339  g_object_class_install_property
340  (gobject_class,
341  PROP_END_DATE,
342  g_param_spec_boxed("end-date",
343  "End Date",
344  "Date for the scheduled transaction to end.",
345  G_TYPE_DATE,
346  G_PARAM_READWRITE));
347 
348  g_object_class_install_property
349  (gobject_class,
350  PROP_LAST_OCCURANCE_DATE,
351  g_param_spec_boxed("last-occurance-date",
352  "Last Occurance Date",
353  "Date for the last occurance of the scheduled transaction.",
354  G_TYPE_DATE,
355  G_PARAM_READWRITE));
356 
357  g_object_class_install_property
358  (gobject_class,
359  PROP_INSTANCE_COUNT,
360  g_param_spec_int ("instance-count",
361  "Instance count",
362  "Number of instances of this scheduled transaction.",
363  0,
364  G_MAXINT16,
365  0,
366  G_PARAM_READWRITE));
367 
368  g_object_class_install_property
369  (gobject_class,
370  PROP_TEMPLATE_ACCOUNT,
371  g_param_spec_object("template-account",
372  "Template account",
373  "Account which holds the template transactions.",
374  GNC_TYPE_ACCOUNT,
375  G_PARAM_READWRITE));
376 }
377 
378 static void
379 xaccSchedXactionInit(SchedXaction *sx, QofBook *book)
380 {
381  Account *ra;
382  const GncGUID *guid;
383  gchar guidstr[GUID_ENCODING_LENGTH+1];
384 
385  qof_instance_init_data (&sx->inst, GNC_ID_SCHEDXACTION, book);
386 
387  /* create a new template account for our splits */
388  sx->template_acct = xaccMallocAccount(book);
389  guid = qof_instance_get_guid( sx );
390  xaccAccountBeginEdit( sx->template_acct );
391  guid_to_string_buff( guid, guidstr );
392  xaccAccountSetName( sx->template_acct, guidstr);
394  (sx->template_acct,
395  gnc_commodity_table_lookup( gnc_commodity_table_get_table(book),
396  "template", "template") );
397  xaccAccountSetType( sx->template_acct, ACCT_TYPE_BANK );
398  xaccAccountCommitEdit( sx->template_acct );
399  ra = gnc_book_get_template_root( book );
400  gnc_account_append_child( ra, sx->template_acct );
401 }
402 
405 {
406  SchedXaction *sx;
407 
408  g_return_val_if_fail (book, NULL);
409 
410  sx = g_object_new(GNC_TYPE_SCHEDXACTION, NULL);
411  xaccSchedXactionInit( sx, book );
412  qof_event_gen( &sx->inst, QOF_EVENT_CREATE , NULL);
413 
414  return sx;
415 }
416 
417 static void
418 sxprivTransMapDelete( gpointer data, gpointer user_data )
419 {
420  Transaction *t = (Transaction *) data;
421  xaccTransBeginEdit( t );
422  xaccTransDestroy( t );
423  xaccTransCommitEdit( t );
424  return;
425 }
426 
427 static void
428 delete_template_trans(SchedXaction *sx)
429 {
430  GList *templ_acct_splits, *curr_split_listref;
431  Split *curr_split;
432  Transaction *split_trans;
433  GList *templ_acct_transactions = NULL;
434 
435  templ_acct_splits
436  = xaccAccountGetSplitList(sx->template_acct);
437 
438  for (curr_split_listref = templ_acct_splits;
439  curr_split_listref;
440  curr_split_listref = curr_split_listref->next)
441  {
442  curr_split = (Split *) curr_split_listref->data;
443  split_trans = xaccSplitGetParent(curr_split);
444  if (! (g_list_find(templ_acct_transactions, split_trans)))
445  {
446  templ_acct_transactions
447  = g_list_prepend(templ_acct_transactions, split_trans);
448  }
449  }
450 
451  g_list_foreach(templ_acct_transactions,
452  sxprivTransMapDelete,
453  NULL);
454 
455  return;
456 }
457 
458 void
459 sx_set_template_account (SchedXaction *sx, Account *account)
460 {
461  Account *old;
462 
463  old = sx->template_acct;
464  sx->template_acct = account;
465  if (old)
466  {
468  xaccAccountDestroy(old);
469  }
470 }
471 
472 void
474 {
475  qof_instance_set_destroying( QOF_INSTANCE(sx), TRUE );
476  gnc_sx_commit_edit( sx );
477 }
478 
479 static void
480 xaccSchedXactionFree( SchedXaction *sx )
481 {
482  GList *l;
483 
484  if ( sx == NULL ) return;
485 
486  qof_event_gen( &sx->inst, QOF_EVENT_DESTROY , NULL);
487 
488  if ( sx->name )
489  g_free( sx->name );
490 
491  /*
492  * we have to delete the transactions in the
493  * template account ourselves
494  */
495 
496  delete_template_trans( sx );
497 
498  /*
499  * xaccAccountDestroy removes the account from
500  * its group for us AFAICT. If shutting down,
501  * the account is being deleted separately.
502  */
503 
505  {
506  xaccAccountBeginEdit(sx->template_acct);
507  xaccAccountDestroy(sx->template_acct);
508  }
509 
510  for ( l = sx->deferredList; l; l = l->next )
511  {
513  l->data = NULL;
514  }
515  if ( sx->deferredList )
516  {
517  g_list_free( sx->deferredList );
518  sx->deferredList = NULL;
519  }
520 
521  /* qof_instance_release (&sx->inst); */
522  g_object_unref( sx );
523 }
524 
525 /* ============================================================ */
526 
527 void
528 gnc_sx_begin_edit (SchedXaction *sx)
529 {
530  qof_begin_edit (&sx->inst);
531 }
532 
533 static void sx_free(QofInstance* inst )
534 {
535  xaccSchedXactionFree( GNC_SX(inst) );
536 }
537 
538 static void commit_err (QofInstance *inst, QofBackendError errcode)
539 {
540  g_critical("Failed to commit: %d", errcode);
541  gnc_engine_signal_commit_error( errcode );
542 }
543 
544 static void commit_done(QofInstance *inst)
545 {
546  qof_event_gen (inst, QOF_EVENT_MODIFY, NULL);
547 }
548 
549 void
550 gnc_sx_commit_edit (SchedXaction *sx)
551 {
552  if (!qof_commit_edit (QOF_INSTANCE(sx))) return;
553  qof_commit_edit_part2 (&sx->inst, commit_err, commit_done, sx_free);
554 }
555 
556 /* ============================================================ */
557 
558 GList*
560 {
561  return sx->schedule;
562 }
563 
564 void
565 gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
566 {
567  g_return_if_fail(sx);
568  gnc_sx_begin_edit(sx);
569  sx->schedule = schedule;
570  qof_instance_set_dirty(&sx->inst);
571  gnc_sx_commit_edit(sx);
572 }
573 
574 gchar *
575 xaccSchedXactionGetName( const SchedXaction *sx )
576 {
577  return sx->name;
578 }
579 
580 void
581 xaccSchedXactionSetName( SchedXaction *sx, const gchar *newName )
582 {
583  g_return_if_fail( newName != NULL );
584  gnc_sx_begin_edit(sx);
585  if ( sx->name != NULL )
586  {
587  g_free( sx->name );
588  sx->name = NULL;
589  }
590  sx->name = g_strdup( newName );
591  qof_instance_set_dirty(&sx->inst);
592  gnc_sx_commit_edit(sx);
593 }
594 
595 const GDate*
596 xaccSchedXactionGetStartDate(const SchedXaction *sx )
597 {
598  g_assert (sx);
599  return &sx->start_date;
600 }
601 
602 void
603 xaccSchedXactionSetStartDate( SchedXaction *sx, const GDate* newStart )
604 {
605  if ( newStart == NULL || !g_date_valid( newStart ))
606  {
607  /* XXX: I reject the bad data - is this the right
608  * thing to do <rgmerk>.
609  * This warning is only human readable - the caller
610  * doesn't know the call failed. This is bad
611  */
612  g_critical("Invalid Start Date");
613  return;
614  }
615  gnc_sx_begin_edit(sx);
616  sx->start_date = *newStart;
617  qof_instance_set_dirty(&sx->inst);
618  gnc_sx_commit_edit(sx);
619 }
620 
621 gboolean
622 xaccSchedXactionHasEndDate( const SchedXaction *sx )
623 {
624  return sx != NULL && g_date_valid( &sx->end_date );
625 }
626 
627 const GDate*
629 {
630  g_assert (sx);
631  return &sx->end_date;
632 }
633 
634 void
635 xaccSchedXactionSetEndDate( SchedXaction *sx, const GDate *newEnd )
636 {
637 /* Note that an invalid GDate IS a permissable value: It means that
638  * the SX is to run "forever". See gnc_sxed_save_sx() and
639  * schedXact_editor_populate() in dialog-sx-editor.c.
640  */
641  if (newEnd == NULL || g_date_compare( newEnd, &sx->start_date ) < 0 )
642  {
643  /* XXX: I reject the bad data - is this the right
644  * thing to do <rgmerk>.
645  * This warning is only human readable - the caller
646  * doesn't know the call failed. This is bad
647  */
648  g_critical("Bad End Date: Invalid or before Start Date");
649  return;
650  }
651 
652  gnc_sx_begin_edit(sx);
653  sx->end_date = *newEnd;
654  qof_instance_set_dirty(&sx->inst);
655  gnc_sx_commit_edit(sx);
656 }
657 
658 const GDate*
659 xaccSchedXactionGetLastOccurDate(const SchedXaction *sx )
660 {
661  return &sx->last_date;
662 }
663 
664 void
665 xaccSchedXactionSetLastOccurDate(SchedXaction *sx, const GDate* new_last_occur)
666 {
667  g_return_if_fail (new_last_occur != NULL);
668  if (g_date_valid(&sx->last_date)
669  && g_date_compare(&sx->last_date, new_last_occur) == 0)
670  return;
671  gnc_sx_begin_edit(sx);
672  sx->last_date = *new_last_occur;
673  qof_instance_set_dirty(&sx->inst);
674  gnc_sx_commit_edit(sx);
675 }
676 
677 gboolean
679 {
680  return ( xaccSchedXactionGetNumOccur( sx ) != 0 );
681 }
682 
683 gint
684 xaccSchedXactionGetNumOccur( const SchedXaction *sx )
685 {
686  return sx->num_occurances_total;
687 }
688 
689 void
691 {
692  if (sx->num_occurances_total == new_num)
693  return;
694  gnc_sx_begin_edit(sx);
695  sx->num_occurances_remain = sx->num_occurances_total = new_num;
696  qof_instance_set_dirty(&sx->inst);
697  gnc_sx_commit_edit(sx);
698 }
699 
700 gint
701 xaccSchedXactionGetRemOccur( const SchedXaction *sx )
702 {
703  return sx->num_occurances_remain;
704 }
705 
706 void
707 xaccSchedXactionSetRemOccur(SchedXaction *sx, gint num_remain)
708 {
709  /* FIXME This condition can be tightened up */
710  if (num_remain > sx->num_occurances_total)
711  {
712  g_warning("number remaining [%d] > total occurrences [%d]",
713  num_remain, sx->num_occurances_total);
714  }
715  else
716  {
717  if (num_remain == sx->num_occurances_remain)
718  return;
719  gnc_sx_begin_edit(sx);
720  sx->num_occurances_remain = num_remain;
721  qof_instance_set_dirty(&sx->inst);
722  gnc_sx_commit_edit(sx);
723  }
724 }
725 
726 gint gnc_sx_get_num_occur_daterange(const SchedXaction *sx, const GDate* start_date, const GDate* end_date)
727 {
728  gint result = 0;
729  SXTmpStateData *tmpState;
730  gboolean countFirstDate;
731 
732  /* SX still active? If not, return now. */
734  && xaccSchedXactionGetRemOccur(sx) <= 0)
735  || (xaccSchedXactionHasEndDate(sx)
736  && g_date_compare(xaccSchedXactionGetEndDate(sx), start_date) < 0))
737  {
738  return result;
739  }
740 
741  tmpState = gnc_sx_create_temporal_state (sx);
742 
743  /* Should we count the first valid date we encounter? Only if the
744  * SX has not yet occurred so far, or if its last valid date was
745  * before the start date. */
746  countFirstDate = !g_date_valid(&tmpState->last_date)
747  || (g_date_compare(&tmpState->last_date, start_date) < 0);
748 
749  /* No valid date? SX has never occurred so far. */
750  if (!g_date_valid(&tmpState->last_date))
751  {
752  /* SX has never occurred so far */
753  gnc_sx_incr_temporal_state (sx, tmpState);
754  if (xaccSchedXactionHasOccurDef(sx) && tmpState->num_occur_rem < 0)
755  {
757  return result;
758  }
759  }
760 
761  /* Increase the tmpState until we are in our interval of
762  * interest. Only calculate anything if the sx hasn't already
763  * ended. */
764  while (g_date_compare(&tmpState->last_date, start_date) < 0)
765  {
766  gnc_sx_incr_temporal_state (sx, tmpState);
767  if (xaccSchedXactionHasOccurDef(sx) && tmpState->num_occur_rem < 0)
768  {
770  return result;
771  }
772  }
773 
774  /* Now we are in our interval of interest. Increment the
775  * occurrence date until we are beyond the end of our
776  * interval. Make sure to check for invalid dates here: It means
777  * the SX has ended. */
778  while (g_date_valid(&tmpState->last_date)
779  && (g_date_compare(&tmpState->last_date, end_date) <= 0)
780  && (!xaccSchedXactionHasEndDate(sx)
781  || g_date_compare(&tmpState->last_date, xaccSchedXactionGetEndDate(sx)) <= 0)
783  /* The >=0 (i.e. the ==) is important here, otherwise
784  * we miss the last valid occurrence of a SX which is
785  * limited by num_occur */
786  || tmpState->num_occur_rem >= 0))
787  {
788  ++result;
789  gnc_sx_incr_temporal_state (sx, tmpState);
790  }
791 
792  /* If the first valid date shouldn't be counted, decrease the
793  * result number by one. */
794  if (!countFirstDate && result > 0)
795  --result;
796 
798  return result;
799 }
800 
801 gboolean
802 xaccSchedXactionGetEnabled( const SchedXaction *sx )
803 {
804  return sx->enabled;
805 }
806 
807 void
808 xaccSchedXactionSetEnabled( SchedXaction *sx, gboolean newEnabled)
809 {
810  gnc_sx_begin_edit(sx);
811  sx->enabled = newEnabled;
812  qof_instance_set_dirty(&sx->inst);
813  gnc_sx_commit_edit(sx);
814 }
815 
816 void
817 xaccSchedXactionGetAutoCreate( const SchedXaction *sx,
818  gboolean *outAutoCreate,
819  gboolean *outNotify )
820 {
821  if (outAutoCreate != NULL)
822  *outAutoCreate = sx->autoCreateOption;
823  if (outNotify != NULL)
824  *outNotify = sx->autoCreateNotify;
825  return;
826 }
827 
828 void
829 xaccSchedXactionSetAutoCreate( SchedXaction *sx,
830  gboolean newAutoCreate,
831  gboolean newNotify )
832 {
833 
834  gnc_sx_begin_edit(sx);
835  sx->autoCreateOption = newAutoCreate;
836  sx->autoCreateNotify = newNotify;
837  qof_instance_set_dirty(&sx->inst);
838  gnc_sx_commit_edit(sx);
839  return;
840 }
841 
842 gint
843 xaccSchedXactionGetAdvanceCreation( const SchedXaction *sx )
844 {
845  return sx->advanceCreateDays;
846 }
847 
848 void
849 xaccSchedXactionSetAdvanceCreation( SchedXaction *sx, gint createDays )
850 {
851  gnc_sx_begin_edit(sx);
852  sx->advanceCreateDays = createDays;
853  qof_instance_set_dirty(&sx->inst);
854  gnc_sx_commit_edit(sx);
855 }
856 
857 gint
858 xaccSchedXactionGetAdvanceReminder( const SchedXaction *sx )
859 {
860  return sx->advanceRemindDays;
861 }
862 
863 void
864 xaccSchedXactionSetAdvanceReminder( SchedXaction *sx, gint reminderDays )
865 {
866  gnc_sx_begin_edit(sx);
867  sx->advanceRemindDays = reminderDays;
868  qof_instance_set_dirty(&sx->inst);
869  gnc_sx_commit_edit(sx);
870 }
871 
872 
873 GDate
875 {
876  GDate last_occur, next_occur, tmpDate;
877 
878  g_date_clear( &last_occur, 1 );
879  g_date_clear( &next_occur, 1 );
880  g_date_clear( &tmpDate, 1 );
881 
882  if ( g_date_valid( &sx->last_date ) )
883  {
884  last_occur = sx->last_date;
885  }
886 
887  if ( stateData != NULL )
888  {
889  SXTmpStateData *tsd = (SXTmpStateData*)stateData;
890  last_occur = tsd->last_date;
891  }
892 
893  if ( g_date_valid( &sx->start_date ) )
894  {
895  if ( g_date_valid(&last_occur) )
896  {
897  last_occur =
898  ( g_date_compare( &last_occur,
899  &sx->start_date ) > 0 ?
900  last_occur : sx->start_date );
901  }
902  else
903  {
904  /* Think about this for a second, and you realize that if the
905  * start date is _today_, we need a last-occur date such that
906  * the 'next instance' is after that date, and equal to the
907  * start date... one day should be good.
908  *
909  * This only holds for the first instance [read: if the
910  * last[-occur]_date is invalid] */
911  last_occur = sx->start_date;
912  g_date_subtract_days( &last_occur, 1 );
913  }
914  }
915 
916  recurrenceListNextInstance(sx->schedule, &last_occur, &next_occur);
917 
918  /* out-of-bounds check */
919  if ( xaccSchedXactionHasEndDate( sx ) )
920  {
921  const GDate *end_date = xaccSchedXactionGetEndDate( sx );
922  if ( g_date_compare( &next_occur, end_date ) > 0 )
923  {
924  g_debug("next_occur past end date");
925  g_date_clear( &next_occur, 1 );
926  }
927  }
928  else if ( xaccSchedXactionHasOccurDef( sx ) )
929  {
930  if ( stateData )
931  {
932  SXTmpStateData *tsd = (SXTmpStateData*)stateData;
933  if ( tsd->num_occur_rem == 0 )
934  {
935  g_debug("no more occurances remain");
936  g_date_clear( &next_occur, 1 );
937  }
938  }
939  else
940  {
941  if ( sx->num_occurances_remain == 0 )
942  {
943  g_date_clear( &next_occur, 1 );
944  }
945  }
946  }
947 
948  return next_occur;
949 }
950 
951 GDate
952 xaccSchedXactionGetInstanceAfter( const SchedXaction *sx,
953  GDate *date,
954  SXTmpStateData *stateData )
955 {
956  GDate prev_occur, next_occur;
957 
958  g_date_clear( &prev_occur, 1 );
959  if ( date )
960  {
961  prev_occur = *date;
962  }
963 
964  if ( stateData != NULL )
965  {
966  SXTmpStateData *tsd = (SXTmpStateData*)stateData;
967  prev_occur = tsd->last_date;
968  }
969 
970  if ( ! g_date_valid( &prev_occur ) )
971  {
972  /* We must be at the beginning. */
973  prev_occur = sx->start_date;
974  g_date_subtract_days( &prev_occur, 1 );
975  }
976 
977  recurrenceListNextInstance(sx->schedule, &prev_occur, &next_occur);
978 
979  if ( xaccSchedXactionHasEndDate( sx ) )
980  {
981  const GDate *end_date = xaccSchedXactionGetEndDate( sx );
982  if ( g_date_compare( &next_occur, end_date ) > 0 )
983  {
984  g_date_clear( &next_occur, 1 );
985  }
986  }
987  else if ( xaccSchedXactionHasOccurDef( sx ) )
988  {
989  if ( stateData )
990  {
991  SXTmpStateData *tsd = (SXTmpStateData*)stateData;
992  if ( tsd->num_occur_rem == 0 )
993  {
994  g_date_clear( &next_occur, 1 );
995  }
996  }
997  else
998  {
999  if ( sx->num_occurances_remain == 0 )
1000  {
1001  g_date_clear( &next_occur, 1 );
1002  }
1003  }
1004  }
1005  return next_occur;
1006 }
1007 
1008 gint
1010 {
1011  gint toRet = -1;
1012  SXTmpStateData *tsd;
1013 
1014  if ( stateData )
1015  {
1016  tsd = (SXTmpStateData*)stateData;
1017  toRet = tsd->num_inst;
1018  }
1019  else
1020  {
1021  toRet = sx->instance_num;
1022  }
1023 
1024  return toRet;
1025 }
1026 
1027 void
1029 {
1030  g_return_if_fail(sx);
1031  if (sx->instance_num == instance_num)
1032  return;
1033  gnc_sx_begin_edit(sx);
1034  sx->instance_num = instance_num;
1035  qof_instance_set_dirty(&sx->inst);
1036  gnc_sx_commit_edit(sx);
1037 }
1038 
1039 GList *
1040 xaccSchedXactionGetSplits( const SchedXaction *sx )
1041 {
1042  g_return_val_if_fail( sx, NULL );
1043  return xaccAccountGetSplitList(sx->template_acct);
1044 }
1045 
1046 static Split *
1047 pack_split_info (TTSplitInfo *s_info, Account *parent_acct,
1048  Transaction *parent_trans, QofBook *book)
1049 {
1050  Split *split;
1051  const gchar *credit_formula;
1052  const gchar *debit_formula;
1053  const GncGUID *acc_guid;
1054 
1055  split = xaccMallocSplit(book);
1056 
1057  xaccSplitSetMemo(split,
1058  gnc_ttsplitinfo_get_memo(s_info));
1059 
1060  /* Set split-action with gnc_set_num_action which is the same as
1061  * xaccSplitSetAction with these arguments */
1062  gnc_set_num_action(NULL, split, NULL,
1063  gnc_ttsplitinfo_get_action(s_info));
1064 
1065  xaccAccountInsertSplit(parent_acct,
1066  split);
1067 
1068  credit_formula = gnc_ttsplitinfo_get_credit_formula(s_info);
1069  debit_formula = gnc_ttsplitinfo_get_debit_formula(s_info);
1070  acc_guid = qof_entity_get_guid(QOF_INSTANCE(gnc_ttsplitinfo_get_account(s_info)));
1071  qof_instance_set (QOF_INSTANCE (split),
1072  "sx-credit-formula", credit_formula,
1073  "sx-debit-formula", debit_formula,
1074  "sx-account", acc_guid,
1075  NULL);
1076 
1077  return split;
1078 }
1079 
1080 
1081 void
1083  QofBook *book)
1084 {
1085  Transaction *new_trans;
1086  TTInfo *tti;
1087  TTSplitInfo *s_info;
1088  Split *new_split;
1089  GList *split_list;
1090 
1091  g_return_if_fail (book);
1092 
1093  /* delete any old transactions, if there are any */
1094  delete_template_trans( sx );
1095 
1096  for (; t_t_list != NULL; t_t_list = t_t_list->next)
1097  {
1098  tti = t_t_list->data;
1099 
1100  new_trans = xaccMallocTransaction(book);
1101 
1102  xaccTransBeginEdit(new_trans);
1103 
1104  xaccTransSetDescription(new_trans,
1105  gnc_ttinfo_get_description(tti));
1106 
1108 
1109  /* Set tran-num with gnc_set_num_action which is the same as
1110  * xaccTransSetNum with these arguments */
1111  gnc_set_num_action(new_trans, NULL,
1112  gnc_ttinfo_get_num(tti), NULL);
1113  xaccTransSetCurrency( new_trans,
1114  gnc_ttinfo_get_currency(tti) );
1115 
1116  for (split_list = gnc_ttinfo_get_template_splits(tti);
1117  split_list;
1118  split_list = split_list->next)
1119  {
1120  s_info = split_list->data;
1121  new_split = pack_split_info(s_info, sx->template_acct,
1122  new_trans, book);
1123  xaccTransAppendSplit(new_trans, new_split);
1124  }
1125  xaccTransCommitEdit(new_trans);
1126  }
1127 }
1128 
1131 {
1132  SXTmpStateData *toRet =
1133  g_new0( SXTmpStateData, 1 );
1134  if (g_date_valid (&(sx->last_date)))
1135  toRet->last_date = sx->last_date;
1136  else
1137  g_date_set_dmy (&(toRet->last_date), 1, 1, 1970);
1138  toRet->num_occur_rem = sx->num_occurances_remain;
1139  toRet->num_inst = sx->instance_num;
1140  return toRet;
1141 }
1142 
1143 void
1145 {
1146  GDate unused;
1147  SXTmpStateData *tsd = (SXTmpStateData*)stateData;
1148 
1149  g_date_clear( &unused, 1 );
1150  tsd->last_date =
1151  xaccSchedXactionGetInstanceAfter( sx,
1152  &unused,
1153  stateData );
1154  if ( xaccSchedXactionHasOccurDef( sx ) )
1155  {
1156  tsd->num_occur_rem -= 1;
1157  }
1158  tsd->num_inst += 1;
1159 }
1160 
1161 void
1163 {
1164  g_free( (SXTmpStateData*)stateData );
1165 }
1166 
1169 {
1170  SXTmpStateData *toRet, *tsd;
1171  tsd = (SXTmpStateData*)stateData;
1172  toRet = g_memdup( tsd, sizeof( SXTmpStateData ) );
1173  return toRet;
1174 }
1175 
1176 static
1177 gint
1178 _temporal_state_data_cmp( gconstpointer a, gconstpointer b )
1179 {
1180  SXTmpStateData *tsd_a, *tsd_b;
1181  tsd_a = (SXTmpStateData*)a;
1182  tsd_b = (SXTmpStateData*)b;
1183 
1184  if ( !tsd_a && !tsd_b )
1185  return 0;
1186  if (tsd_a == tsd_b)
1187  return 0;
1188  if ( !tsd_a )
1189  return 1;
1190  if ( !tsd_b )
1191  return -1;
1192  return g_date_compare( &tsd_a->last_date,
1193  &tsd_b->last_date );
1194 }
1195 
1200 void
1201 gnc_sx_add_defer_instance( SchedXaction *sx, void *deferStateData )
1202 {
1203  sx->deferredList = g_list_insert_sorted( sx->deferredList,
1204  deferStateData,
1205  _temporal_state_data_cmp );
1206 }
1207 
1212 void
1213 gnc_sx_remove_defer_instance( SchedXaction *sx, void *deferStateData )
1214 {
1215  GList *found_by_value;
1216 
1217  found_by_value = g_list_find_custom(
1218  sx->deferredList, deferStateData, _temporal_state_data_cmp);
1219  if (found_by_value == NULL)
1220  {
1221  g_warning("unable to find deferred instance");
1222  return;
1223  }
1224 
1225  gnc_sx_destroy_temporal_state(found_by_value->data);
1226  sx->deferredList = g_list_delete_link(sx->deferredList, found_by_value);
1227 }
1228 
1238 GList*
1240 {
1241  return sx->deferredList;
1242 }
1243 
1244 static void
1245 destroy_sx_on_book_close(QofInstance *ent, gpointer data)
1246 {
1247  SchedXaction* sx = GNC_SCHEDXACTION(ent);
1248 
1249  gnc_sx_begin_edit(sx);
1251 }
1252 
1258 static void
1259 gnc_sx_book_end(QofBook* book)
1260 {
1261  QofCollection *col;
1262 
1263  col = qof_book_get_collection(book, GNC_ID_SCHEDXACTION);
1264  qof_collection_foreach(col, destroy_sx_on_book_close, NULL);
1265 }
1266 
1267 #ifdef _MSC_VER
1268 /* MSVC compiler doesn't have C99 "designated initializers"
1269  * so we wrap them in a macro that is empty on MSVC. */
1270 # define DI(x) /* */
1271 #else
1272 # define DI(x) x
1273 #endif
1274 static QofObject SXDesc =
1275 {
1276  DI(.interface_version = ) QOF_OBJECT_VERSION,
1277  DI(.e_type = ) GNC_SX_ID,
1278  DI(.type_label = ) "Scheduled Transaction",
1279  DI(.create = ) (gpointer)xaccSchedXactionMalloc,
1280  DI(.book_begin = ) NULL,
1281  DI(.book_end = ) gnc_sx_book_end,
1282  DI(.is_dirty = ) qof_collection_is_dirty,
1283  DI(.mark_clean = ) qof_collection_mark_clean,
1284  DI(.foreach = ) qof_collection_foreach,
1285  DI(.printable = ) NULL,
1286  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
1287 };
1288 
1289 gboolean
1291 {
1292  static QofParam params[] =
1293  {
1294  {
1295  GNC_SX_NAME, QOF_TYPE_STRING, (QofAccessFunc)xaccSchedXactionGetName,
1297  },
1298  {
1299  GNC_SX_START_DATE, QOF_TYPE_DATE, (QofAccessFunc)xaccSchedXactionGetStartDate,
1300  (QofSetterFunc)xaccSchedXactionSetStartDate
1301  },
1302  {
1303  GNC_SX_LAST_DATE, QOF_TYPE_DATE, (QofAccessFunc)xaccSchedXactionGetLastOccurDate,
1304  (QofSetterFunc)xaccSchedXactionSetLastOccurDate
1305  },
1306  {
1307  GNC_SX_NUM_OCCUR, QOF_TYPE_INT64, (QofAccessFunc)xaccSchedXactionGetNumOccur,
1309  },
1310  {
1311  GNC_SX_REM_OCCUR, QOF_TYPE_INT64, (QofAccessFunc)xaccSchedXactionGetRemOccur,
1312  (QofSetterFunc)xaccSchedXactionSetRemOccur
1313  },
1314  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
1315  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
1316  { NULL },
1317  };
1318  qof_class_register(GNC_SX_ID, NULL, params);
1319  return qof_object_register(&SXDesc);
1320 }
const GDate * xaccSchedXactionGetEndDate(const SchedXaction *sx)
Definition: SchedXaction.c:628
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Definition: Account.c:2208
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
#define xaccTransAppendSplit(t, s)
Definition: Transaction.h:357
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
Definition: SchedXaction.c:565
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Transaction * xaccMallocTransaction(QofBook *book)
Definition: Transaction.c:513
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
Definition: Transaction.c:1920
GList * gnc_sx_get_schedule(const SchedXaction *sx)
Definition: SchedXaction.c:559
void gnc_account_append_child(Account *new_parent, Account *child)
Definition: Account.c:2525
const GncGUID * qof_instance_get_guid(gconstpointer)
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3717
void gnc_sx_destroy_temporal_state(SXTmpStateData *stateData)
QofBook * qof_instance_get_book(gconstpointer)
gboolean qof_collection_is_dirty(const QofCollection *col)
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
Definition: SchedXaction.c:690
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:59
SXTmpStateData * gnc_sx_create_temporal_state(const SchedXaction *sx)
void qof_instance_set(QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_fcn, const QofParam *params)
void xaccTransSetDescription(Transaction *trans, const char *desc)
Definition: Transaction.c:2085
Account * gnc_book_get_template_root(const QofBook *book)
Definition: SX-book.c:65
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
Definition: qofclass.h:177
#define QOF_OBJECT_VERSION
Definition: qofobject.h:64
gboolean qof_commit_edit(QofInstance *inst)
#define QOF_PARAM_BOOK
Definition: qofquery.h:109
void qof_collection_foreach(const QofCollection *, QofInstanceForeachCB, gpointer user_data)
GDate xaccSchedXactionGetNextInstance(const SchedXaction *sx, SXTmpStateData *stateData)
Returns the next occurrence of a scheduled transaction.
Definition: SchedXaction.c:874
Definition: guid.h:65
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1354
void xaccTransDestroy(Transaction *trans)
Definition: Transaction.c:1402
gboolean SXRegister(void)
QOF registration.
void xaccAccountDestroy(Account *acc)
Definition: Account.c:1400
void qof_instance_init_data(QofInstance *, QofIdType, QofBook *)
gboolean qof_begin_edit(QofInstance *inst)
void gnc_sx_incr_temporal_state(const SchedXaction *sx, SXTmpStateData *stateData)
Account handling public routines.
void xaccSplitSetMemo(Split *split, const char *memo)
Definition: Split.c:1774
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
GList * deferredList
Definition: SchedXaction.h:118
void gnc_sx_add_defer_instance(SchedXaction *sx, void *deferStateData)
Adds an instance to the deferred list of the SX.
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
gint gnc_sx_get_num_occur_daterange(const SchedXaction *sx, const GDate *start_date, const GDate *end_date)
Definition: SchedXaction.c:726
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
SXTmpStateData * gnc_sx_clone_temporal_state(SXTmpStateData *stateData)
Allocates and returns a one-by-one copy of the given temporal state.
void qof_collection_mark_clean(QofCollection *)
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
void xaccSchedXactionSetTemplateTrans(SchedXaction *sx, GList *t_t_list, QofBook *book)
Set the schedxaction's template transaction.
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
All type declarations for the whole Gnucash engine.
const GncGUID * qof_entity_get_guid(gconstpointer)
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
Definition: SchedXaction.c:581
Definition: SplitP.h:71
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
#define xaccAccountInsertSplit(acc, s)
Definition: Account.h:972
void(* QofSetterFunc)(gpointer, gpointer)
Definition: qofclass.h:184
void gnc_sx_remove_defer_instance(SchedXaction *sx, void *deferStateData)
Removes an instance from the deferred list.
Account * xaccMallocAccount(QofBook *book)
Definition: Account.c:1083
time64 gnc_time(time64 *tbuf)
get the current local time
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Definition: SchedXaction.c:404
QofCollection * qof_book_get_collection(const QofBook *, QofIdType)
gboolean qof_object_register(const QofObject *object)
gboolean qof_book_shutting_down(const QofBook *book)
void qof_event_gen(QofInstance *entity, QofEventId event_type, gpointer event_data)
Invoke all registered event handlers using the given arguments.
gboolean xaccSchedXactionHasOccurDef(const SchedXaction *sx)
Definition: SchedXaction.c:678
Scheduled Transactions public handling routines.
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
Definition: SchedXaction.c:635
API for Transactions and Splits (journal entries)
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void xaccAccountSetName(Account *acc, const char *str)
Definition: Account.c:2229
void xaccSchedXactionDestroy(SchedXaction *sx)
Definition: SchedXaction.c:473
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389
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.