35 #include <glib-object.h>
46 #include "gnc-exp-parser.h"
54 #define G_LOG_DOMAIN "gnc.app-utils.sx"
56 static GObjectClass *parent_class = NULL;
59 static void gnc_sx_instance_model_init(GTypeInstance *instance, gpointer klass);
62 static GncSxInstance* gnc_sx_instance_new(
GncSxInstances *parent, GncSxInstanceState state, GDate *date,
void *temporal_state, gint sequence_num);
64 static gint _get_vars_helper(
Transaction *txn,
void *var_hash_data);
68 static void _gnc_sx_instance_event_handler(
QofInstance *ent,
QofEventId event_type, gpointer user_data, gpointer evt_data);
73 _sx_var_to_raw_numeric(gchar *name,
GncSxVariable *var, GHashTable *parser_var_hash)
75 g_hash_table_insert(parser_var_hash, g_strdup(name), &var->
value);
79 _var_numeric_to_sx_var(gchar *name,
gnc_numeric *num, GHashTable *sx_var_hash)
82 if (!g_hash_table_lookup_extended(sx_var_hash, name, NULL, &p_var))
84 p_var = (gpointer)gnc_sx_variable_new(name);
85 g_hash_table_insert(sx_var_hash, g_strdup(name), p_var);
91 _wipe_parsed_sx_var(gchar *key,
GncSxVariable *var, gpointer unused_user_data)
102 GHashTable *parser_vars;
103 parser_vars = g_hash_table_new(g_str_hash, g_str_equal);
104 g_hash_table_foreach(instance_var_hash, (GHFunc)_sx_var_to_raw_numeric, parser_vars);
109 gnc_sx_parse_vars_from_formula(
const char *formula,
110 GHashTable *var_hash,
116 GHashTable *parser_vars;
121 num = gnc_numeric_zero();
122 if (!gnc_exp_parser_parse_separate_vars(formula, &num, &errLoc, parser_vars))
128 g_hash_table_foreach(parser_vars, (GHFunc)_var_numeric_to_sx_var, var_hash);
129 g_hash_table_destroy(parser_vars);
140 gnc_sx_variable_new(gchar *name)
143 var->name = g_strdup(name);
145 var->editable = TRUE;
150 gnc_sx_variable_new_full(gchar *name,
gnc_numeric value, gboolean editable)
154 var->editable = editable;
163 var->editable = to_copy->editable;
175 _get_vars_helper(
Transaction *txn,
void *var_hash_data)
177 GHashTable *var_hash = (GHashTable*)var_hash_data;
180 gchar *credit_formula = NULL;
181 gchar *debit_formula = NULL;
185 if (split_list == NULL)
190 for ( ; split_list; split_list = split_list->next)
196 s = (
Split*)split_list->data;
199 "sx-account", &acct_guid,
200 "sx-credit-formula", &credit_formula,
201 "sx-debit-formula", &debit_formula,
205 if (first_cmdty == NULL)
207 first_cmdty = split_cmdty;
214 const gchar *split_mnemonic, *first_mnemonic;
216 var_name = g_string_sized_new(16);
219 g_string_printf(var_name,
"%s -> %s",
220 split_mnemonic ? split_mnemonic :
"(null)",
221 first_mnemonic ? first_mnemonic :
"(null)");
222 var = gnc_sx_variable_new(g_strdup(var_name->str));
223 g_hash_table_insert(var_hash, g_strdup(var->name), var);
224 g_string_free(var_name, TRUE);
228 if (credit_formula && strlen(credit_formula) != 0)
230 gnc_sx_parse_vars_from_formula(credit_formula, var_hash, NULL);
232 if (debit_formula && strlen(debit_formula) != 0)
234 gnc_sx_parse_vars_from_formula(debit_formula, var_hash, NULL);
236 g_free (credit_formula);
237 g_free (debit_formula);
244 gnc_sx_get_template_transaction_account(
const SchedXaction *sx)
246 Account *template_root, *sx_template_acct;
252 return sx_template_acct;
256 gnc_sx_get_variables(
SchedXaction *sx, GHashTable *var_hash)
259 sx_template_acct = gnc_sx_get_template_transaction_account(sx);
264 _set_var_to_random_value(gchar *key,
GncSxVariable *var, gpointer unused_user_data)
272 gnc_sx_randomize_variables(GHashTable *vars)
274 g_hash_table_foreach(vars, (GHFunc)_set_var_to_random_value, NULL);
278 _clone_sx_var_hash_entry(gpointer key, gpointer value, gpointer user_data)
280 GHashTable *to = (GHashTable*)user_data;
283 g_hash_table_insert(to, g_strdup(key), var);
287 gnc_sx_instance_new(
GncSxInstances *parent, GncSxInstanceState state, GDate *date,
void *temporal_state, gint sequence_num)
293 g_date_clear(&rtn->
date, 1);
297 if (! parent->variable_names_parsed)
299 parent->
variable_names = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)gnc_sx_variable_free);
301 g_hash_table_foreach(parent->
variable_names, (GHFunc)_wipe_parsed_sx_var, NULL);
302 parent->variable_names_parsed = TRUE;
305 rtn->
variable_bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)gnc_sx_variable_free);
309 int instance_i_value;
314 i_num = gnc_numeric_create(instance_i_value, 1);
315 as_var = gnc_sx_variable_new_full(
"i", i_num, FALSE);
324 _compare_GncSxVariables(gconstpointer a, gconstpointer b)
330 _build_list_from_hash_elts(gpointer key, gpointer value, gpointer user_data)
332 GList **list = (GList**)user_data;
333 *list = g_list_insert_sorted(*list, value, _compare_GncSxVariables);
340 g_hash_table_foreach(inst->
variable_bindings, _build_list_from_hash_elts, &vars);
345 _gnc_sx_gen_instances(gpointer *data, gpointer user_data)
349 const GDate *range_end = (
const GDate*)user_data;
350 GDate creation_end, remind_end;
356 creation_end = *range_end;
357 g_date_add_days(&creation_end, xaccSchedXactionGetAdvanceCreation(sx));
358 remind_end = creation_end;
359 g_date_add_days(&remind_end, xaccSchedXactionGetAdvanceReminder(sx));
364 for ( ; postponed != NULL; postponed = postponed->next)
370 g_date_clear(&inst_date, 1);
373 inst = gnc_sx_instance_new(instances, SX_INSTANCE_STATE_POSTPONED, &inst_date, postponed->data, seq_num);
379 g_date_clear(&cur_date, 1);
381 cur_date = xaccSchedXactionGetInstanceAfter(sx, &cur_date, sequence_ctx);
382 instances->next_instance_date = cur_date;
383 while (g_date_valid(&cur_date) && g_date_compare(&cur_date, &creation_end) <= 0)
388 inst = gnc_sx_instance_new(instances, SX_INSTANCE_STATE_TO_CREATE, &cur_date, sequence_ctx, seq_num);
391 cur_date = xaccSchedXactionGetInstanceAfter(sx, &cur_date, sequence_ctx);
395 while (g_date_valid(&cur_date) && g_date_compare(&cur_date, &remind_end) <= 0)
400 inst = gnc_sx_instance_new(instances, SX_INSTANCE_STATE_REMINDER, &cur_date, sequence_ctx, seq_num);
403 cur_date = xaccSchedXactionGetInstanceAfter(sx, &cur_date, sequence_ctx);
413 g_date_clear(&now, 1);
421 GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
424 g_assert(range_end != NULL);
425 g_assert(g_date_valid(range_end));
427 instances = gnc_sx_instance_model_new();
428 instances->include_disabled = include_disabled;
429 instances->range_end = *range_end;
431 if (include_disabled)
433 instances->sx_instance_list =
gnc_g_list_map(all_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
437 GList *sx_iter = g_list_first(all_sxes);
438 GList *enabled_sxes = NULL;
440 for (; sx_iter != NULL; sx_iter = sx_iter->next)
443 if (xaccSchedXactionGetEnabled(sx))
445 enabled_sxes = g_list_append(enabled_sxes, sx);
448 instances->sx_instance_list =
gnc_g_list_map(enabled_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
449 g_list_free(enabled_sxes);
455 gnc_sx_instance_model_new(
void)
457 return GNC_SX_INSTANCE_MODEL(g_object_new(GNC_TYPE_SX_INSTANCE_MODEL, NULL));
461 gnc_sx_instance_model_get_type(
void)
463 static GType type = 0;
466 static const GTypeInfo info =
471 (GClassInitFunc)gnc_sx_instance_model_class_init,
476 (GInstanceInitFunc)gnc_sx_instance_model_init
478 type = g_type_register_static (G_TYPE_OBJECT,
479 "GncSxInstanceModelType",
486 gnc_sx_instance_model_dispose(GObject *
object)
489 g_return_if_fail(
object != NULL);
490 model = GNC_SX_INSTANCE_MODEL(
object);
492 g_return_if_fail(!model->disposed);
493 model->disposed = TRUE;
497 G_OBJECT_CLASS(parent_class)->dispose(
object);
517 GList *instance_iter;
525 instances->sx = NULL;
527 for (instance_iter = instances->
instance_list; instance_iter != NULL; instance_iter = instance_iter->next)
530 gnc_sx_instance_free(inst);
539 gnc_sx_instance_model_finalize (GObject *
object)
544 g_return_if_fail(
object != NULL);
546 model = GNC_SX_INSTANCE_MODEL(
object);
547 for (sx_list_iter = model->sx_instance_list; sx_list_iter != NULL; sx_list_iter = sx_list_iter->next)
550 gnc_sx_instances_free(instances);
552 g_list_free(model->sx_instance_list);
553 model->sx_instance_list = NULL;
555 G_OBJECT_CLASS(parent_class)->finalize(
object);
561 GObjectClass *object_class = G_OBJECT_CLASS(klass);
563 parent_class = g_type_class_peek_parent(klass);
565 object_class->dispose = gnc_sx_instance_model_dispose;
566 object_class->finalize = gnc_sx_instance_model_finalize;
568 klass->removing_signal_id =
569 g_signal_new(
"removing",
570 GNC_TYPE_SX_INSTANCE_MODEL,
575 g_cclosure_marshal_VOID__POINTER,
580 klass->updated_signal_id =
581 g_signal_new(
"updated",
582 GNC_TYPE_SX_INSTANCE_MODEL,
587 g_cclosure_marshal_VOID__POINTER,
592 klass->added_signal_id =
593 g_signal_new(
"added",
594 GNC_TYPE_SX_INSTANCE_MODEL,
599 g_cclosure_marshal_VOID__POINTER,
606 gnc_sx_instance_model_init(GTypeInstance *instance, gpointer klass)
610 g_date_clear(&inst->range_end, 1);
611 inst->sx_instance_list = NULL;
618 if (in_list_instances->sx == sx_to_find)
624 _gnc_sx_instance_event_handler(
QofInstance *ent,
QofEventId event_type, gpointer user_data, gpointer evt_data)
633 if (!(GNC_IS_SX(ent) || GNC_IS_SXES(ent)))
639 gboolean sx_is_in_model = FALSE;
643 sx_is_in_model = (g_list_find_custom(instances->sx_instance_list, sx, (GCompareFunc)_gnc_sx_instance_find_by_sx) != NULL);
644 if (event_type & QOF_EVENT_MODIFY)
648 if (instances->include_disabled || xaccSchedXactionGetEnabled(sx))
650 g_signal_emit_by_name(instances,
"updated", (gpointer)sx);
655 g_signal_emit_by_name(instances,
"removing", (gpointer)sx);
661 GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
662 if (g_list_find(all_sxes, sx) && (!instances->include_disabled && xaccSchedXactionGetEnabled(sx)))
665 instances->sx_instance_list
666 = g_list_append(instances->sx_instance_list,
667 _gnc_sx_gen_instances((gpointer)sx, (gpointer) & instances->range_end));
668 g_signal_emit_by_name(instances,
"added", (gpointer)sx);
674 else if (GNC_IS_SXES(ent))
678 if (event_type & GNC_EVENT_ITEM_REMOVED)
680 GList *instances_link;
681 instances_link = g_list_find_custom(instances->sx_instance_list, sx, (GCompareFunc)_gnc_sx_instance_find_by_sx);
682 if (instances_link != NULL)
684 g_signal_emit_by_name(instances,
"removing", (gpointer)sx);
686 else if (instances->include_disabled)
688 g_warning(
"could not remove instances that do not exist in the model");
693 if (instances->include_disabled || xaccSchedXactionGetEnabled(sx))
696 instances->sx_instance_list
697 = g_list_append(instances->sx_instance_list,
698 _gnc_sx_gen_instances((gpointer)sx, (gpointer) & instances->range_end));
699 g_signal_emit_by_name(instances,
"added", (gpointer)sx);
713 _find_unreferenced_vars(gchar *key,
717 if (!g_hash_table_lookup_extended(cb_pair->hash, key, NULL, NULL))
719 g_debug(
"variable [%s] not found", key);
720 cb_pair->list = g_list_append(cb_pair->list, key);
730 link = g_list_find_custom(model->sx_instance_list, sx, (GCompareFunc)_gnc_sx_instance_find_by_sx);
733 g_critical(
"couldn't find sx [%p]\n", sx);
739 new_instances = _gnc_sx_gen_instances((gpointer)sx, &model->range_end);
740 existing->sx = new_instances->sx;
741 existing->next_instance_date = new_instances->next_instance_date;
743 GList *existing_iter, *new_iter;
744 gboolean existing_remain, new_remain;
751 for (; existing_iter != NULL && new_iter != NULL; existing_iter = existing_iter->next, new_iter = new_iter->next)
754 gboolean same_instance_date;
758 same_instance_date = g_date_compare(&existing_inst->
date, &new_inst->
date) == 0;
759 if (!same_instance_date)
763 existing_remain = (existing_iter != NULL);
764 new_remain = (new_iter != NULL);
770 g_list_foreach(existing_iter, (GFunc)gnc_sx_instance_free, NULL);
776 GList *new_iter_iter;
779 for (new_iter_iter = new_iter; new_iter_iter != NULL; new_iter_iter = new_iter_iter->next)
785 g_list_free(new_iter);
792 GList *removed_var_names = NULL, *added_var_names = NULL;
793 GList *inst_iter = NULL;
796 removed_cb_data.list = NULL;
797 g_hash_table_foreach(existing->
variable_names, (GHFunc)_find_unreferenced_vars, &removed_cb_data);
798 removed_var_names = removed_cb_data.list;
799 g_debug(
"%d removed variables", g_list_length(removed_var_names));
802 added_cb_data.list = NULL;
803 g_hash_table_foreach(new_instances->
variable_names, (GHFunc)_find_unreferenced_vars, &added_cb_data);
804 added_var_names = added_cb_data.list;
805 g_debug(
"%d added variables", g_list_length(added_var_names));
814 for (inst_iter = existing->
instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
819 for (var_iter = removed_var_names; var_iter != NULL; var_iter = var_iter->next)
821 gchar *to_remove_key = (gchar*)var_iter->data;
825 for (var_iter = added_var_names; var_iter != NULL; var_iter = var_iter->next)
827 gchar *to_add_key = (gchar*)var_iter->data;
828 if (!g_hash_table_lookup_extended(
835 g_assert(parent_var != NULL);
836 var_copy = gnc_sx_variable_new_copy(parent_var);
842 gnc_sx_instances_free(new_instances);
848 GList *instance_link = NULL;
850 instance_link = g_list_find_custom(model->sx_instance_list, sx, (GCompareFunc)_gnc_sx_instance_find_by_sx);
851 if (instance_link == NULL)
853 g_warning(
"instance not found!\n");
857 model->sx_instance_list = g_list_remove_link(model->sx_instance_list, instance_link);
862 increment_sx_state(
GncSxInstance *inst, GDate **last_occur_date,
int *instance_count,
int *remain_occur_count)
864 if (!g_date_valid(*last_occur_date)
865 || (g_date_valid(*last_occur_date)
866 && g_date_compare(*last_occur_date, &inst->
date) <= 0))
868 *last_occur_date = &inst->
date;
873 if (*remain_occur_count > 0)
875 *remain_occur_count -= 1;
882 GList **created_txn_guids;
883 GList **creation_errors;
888 const Split *template_split,
890 GList **creation_errors)
894 "sx-account", &acct_guid,
897 if (*split_acct == NULL)
902 err = g_string_new(
"");
903 g_string_printf(err,
"Unknown account for guid [%s], cancelling SX [%s] creation.",
904 guid_str, xaccSchedXactionGetName(sx));
905 g_critical(
"%s", err->str);
906 if (creation_errors != NULL)
907 *creation_errors = g_list_append(*creation_errors, err);
909 g_string_free(err, TRUE);
918 const Split *template_split,
920 GList **creation_errors,
921 const char *formula_key,
922 const char* numeric_key,
923 GHashTable *variable_bindings)
926 char *formula_str = NULL, *parseErrorLoc = NULL;
929 formula_key, &formula_str,
930 numeric_key, &numeric_val,
933 if (numeric_val != NULL &&
940 numeric->num = numeric_val->num;
941 numeric->denom = numeric_val->denom;
945 if (formula_str != NULL && strlen(formula_str) != 0)
947 GHashTable *parser_vars = NULL;
948 if (variable_bindings)
952 if (!gnc_exp_parser_parse_separate_vars(formula_str,
957 GString *err = g_string_new(
"");
958 g_string_printf(err,
"Error parsing SX [%s] key [%s]=formula [%s] at [%s]: %s",
959 xaccSchedXactionGetName(sx),
963 gnc_exp_parser_error_string());
964 g_critical(
"%s", err->str);
965 if (creation_errors != NULL)
966 *creation_errors = g_list_append(*creation_errors, err);
968 g_string_free(err, TRUE);
971 if (parser_vars != NULL)
973 g_hash_table_destroy(parser_vars);
981 _get_sx_formula_value(instance->
parent->sx, template_split, credit_num,
982 creation_errors,
"sx-credit-formula",
989 _get_sx_formula_value(instance->
parent->sx, template_split, debit_num,
990 creation_errors,
"sx-debit-formula",
995 create_each_transaction_helper(
Transaction *template_txn,
void *user_data)
998 GList *txn_splits, *template_splits;
999 Split *copying_split;
1001 gboolean err_flag = FALSE;
1013 g_debug(
"creating template txn desc [%s] for sx [%s]",
1015 xaccSchedXactionGetName(creation_data->instance->
parent->sx));
1026 g_date_get_day(&creation_data->instance->
date),
1027 g_date_get_month(&creation_data->instance->
date),
1028 g_date_get_year(&creation_data->instance->
date));
1033 if ((template_splits == NULL) || (txn_splits == NULL))
1035 g_critical(
"transaction w/o splits for sx [%s]",
1036 xaccSchedXactionGetName(creation_data->instance->
parent->sx));
1043 txn_splits && template_splits;
1044 txn_splits = txn_splits->next, template_splits = template_splits->next)
1046 const Split *template_split;
1053 template_split = (
Split*)template_splits->data;
1054 copying_split = (
Split*)txn_splits->data;
1056 if (!_get_template_split_account(creation_data->instance->
parent->sx, template_split, &split_acct, creation_data->creation_errors))
1063 if (first_cmdty == NULL)
1075 xaccSplitSetAccount(copying_split, split_acct);
1081 credit_num = gnc_numeric_zero();
1082 debit_num = gnc_numeric_zero();
1084 _get_credit_formula_value(creation_data->instance, template_split, &credit_num, creation_data->creation_errors);
1085 _get_debit_formula_value(creation_data->instance, template_split, &debit_num, creation_data->creation_errors);
1087 final = gnc_numeric_sub_fixed( debit_num, credit_num );
1092 GString *err = g_string_new(
"");
1093 g_string_printf(err,
"error %d in SX [%s] final gnc_numeric value, using 0 instead",
1094 gncn_error, xaccSchedXactionGetName(creation_data->instance->
parent->sx));
1095 g_critical(
"%s", err->str);
1096 if (creation_data->creation_errors != NULL)
1097 *creation_data->creation_errors = g_list_append(*creation_data->creation_errors, err);
1099 g_string_free(err, TRUE);
1100 final = gnc_numeric_zero();
1107 GString *exchange_rate_var_name = g_string_sized_new(16);
1142 exchange_rate = gnc_numeric_create (1, 1);
1143 g_string_printf(exchange_rate_var_name,
"%s -> %s",
1151 exchange_rate_var_name->str);
1153 if (exchange_rate_var != NULL)
1155 exchange_rate = exchange_rate_var->
value;
1158 g_string_free(exchange_rate_var_name, TRUE);
1176 g_critical(
"new transaction creation sx [%s]",
1177 xaccSchedXactionGetName(creation_data->instance->
parent->sx));
1185 "from-sched-xaction",
1192 if (creation_data->created_txn_guids != NULL)
1194 *creation_data->created_txn_guids
1195 = g_list_append(*(creation_data->created_txn_guids), (gpointer)
xaccTransGetGUID(new_txn));
1202 create_transactions_for_instance(
GncSxInstance *instance, GList **created_txn_guids, GList **creation_errors)
1207 sx_template_account = gnc_sx_get_template_transaction_account(instance->
parent->sx);
1209 creation_data.instance = instance;
1210 creation_data.created_txn_guids = created_txn_guids;
1211 creation_data.creation_errors = creation_errors;
1214 create_each_transaction_helper,
1220 gboolean auto_create_only,
1221 GList **created_transaction_guids,
1222 GList **creation_errors)
1232 for (iter = model->sx_instance_list; iter != NULL; iter = iter->next)
1234 GList *instance_iter;
1236 GDate *last_occur_date;
1237 gint instance_count = 0;
1238 gint remain_occur_count = 0;
1246 last_occur_date = (GDate*) xaccSchedXactionGetLastOccurDate(instances->sx);
1248 remain_occur_count = xaccSchedXactionGetRemOccur(instances->sx);
1250 for (instance_iter = instances->
instance_list; instance_iter != NULL; instance_iter = instance_iter->next)
1253 gboolean sx_is_auto_create;
1255 xaccSchedXactionGetAutoCreate(inst->
parent->sx, &sx_is_auto_create, NULL);
1256 if (auto_create_only && !sx_is_auto_create)
1258 if (inst->
state != SX_INSTANCE_STATE_TO_CREATE)
1265 if (inst->
orig_state == SX_INSTANCE_STATE_POSTPONED
1266 && inst->
state != SX_INSTANCE_STATE_POSTPONED)
1273 switch (inst->
state)
1275 case SX_INSTANCE_STATE_CREATED:
1278 case SX_INSTANCE_STATE_IGNORED:
1279 increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
1281 case SX_INSTANCE_STATE_POSTPONED:
1282 if (inst->
orig_state != SX_INSTANCE_STATE_POSTPONED)
1287 increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
1289 case SX_INSTANCE_STATE_TO_CREATE:
1290 create_transactions_for_instance(inst, created_transaction_guids, creation_errors);
1291 increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
1294 case SX_INSTANCE_STATE_REMINDER:
1299 g_assert_not_reached();
1304 xaccSchedXactionSetLastOccurDate(instances->sx, last_occur_date);
1306 xaccSchedXactionSetRemOccur(instances->sx, remain_occur_count);
1313 GncSxInstanceState new_state)
1315 if (instance->
state == new_state)
1318 instance->
state = new_state;
1324 g_assert(inst_iter != NULL);
1325 if (instance->
state != SX_INSTANCE_STATE_REMINDER)
1328 for (inst_iter = inst_iter->prev; inst_iter != NULL; inst_iter = inst_iter->prev)
1331 if (prev_inst->
state != SX_INSTANCE_STATE_REMINDER)
1333 prev_inst->
state = SX_INSTANCE_STATE_POSTPONED;
1339 for (inst_iter = inst_iter->next; inst_iter != NULL; inst_iter = inst_iter->next)
1342 if (next_inst->
state == SX_INSTANCE_STATE_REMINDER)
1344 next_inst->
state = SX_INSTANCE_STATE_REMINDER;
1349 g_signal_emit_by_name(model,
"updated", (gpointer)instance->
parent->sx);
1361 variable->
value = *new_value;
1362 g_signal_emit_by_name(model,
"updated", (gpointer)instance->
parent->sx);
1366 _list_from_hash_elts(gpointer key, gpointer value, GList **result_list)
1368 *result_list = g_list_append(*result_list, value);
1375 GList *sx_iter, *inst_iter, *var_list = NULL, *var_iter;
1377 for (sx_iter = model->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
1380 for (inst_iter = instances->
instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
1384 if (inst->
state != SX_INSTANCE_STATE_TO_CREATE)
1387 g_hash_table_foreach(inst->
variable_bindings, (GHFunc)_list_from_hash_elts, &var_list);
1388 for (var_iter = var_list; var_iter != NULL; var_iter = var_iter->next)
1394 need->instance = inst;
1395 need->variable = var;
1396 rtn = g_list_append(rtn, need);
1399 g_list_free(var_list);
1409 GList *sx_iter, *inst_iter;
1411 g_return_if_fail(model != NULL);
1412 g_return_if_fail(summary != NULL);
1420 for (sx_iter = model->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
1423 gboolean sx_is_auto_create = FALSE, sx_notify = FALSE;
1424 xaccSchedXactionGetAutoCreate(instances->sx, &sx_is_auto_create, &sx_notify);
1425 for (inst_iter = instances->
instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
1430 if (inst->
state == SX_INSTANCE_STATE_TO_CREATE)
1432 if (sx_is_auto_create)
1465 g_message(
"need dialog? %s", summary->
need_dialog ?
"true" :
"false");
1468 static void gnc_numeric_free(gpointer data)
1477 NULL, gnc_numeric_free);
1483 GList **creation_errors;
1488 static void add_to_hash_amount(GHashTable* hash,
const GncGUID* guid,
const gnc_numeric* amount)
1493 gnc_numeric* elem = g_hash_table_lookup(hash, guid);
1499 *elem = gnc_numeric_zero();
1500 g_hash_table_insert(hash, (gpointer) guid, elem);
1506 g_critical(
"Oops, the given amount [%s] has the error code %d, at guid [%s].",
1514 g_critical(
"Oops, the account's amount [%s] has the error code %d, at guid [%s].",
1532 g_critical(
"Oops, after addition at guid [%s] the resulting amount [%s] has the error code %d; added amount = [%s].",
1541 g_debug(
"Adding to guid [%s] the value [%s]. Value now [%s].",
1548 create_cashflow_helper(
Transaction *template_txn,
void *user_data)
1551 GList *template_splits;
1554 g_debug(
"Evaluating txn desc [%s] for sx [%s]",
1556 xaccSchedXactionGetName(creation_data->sx));
1563 if (template_splits == NULL)
1565 g_critical(
"transaction w/o splits for sx [%s]",
1566 xaccSchedXactionGetName(creation_data->sx));
1572 template_splits = template_splits->next)
1576 const Split *template_split = (
const Split*) template_splits->data;
1579 if (!_get_template_split_account(creation_data->sx, template_split, &split_acct, creation_data->creation_errors))
1581 g_debug(
"Could not find account for split");
1587 if (first_cmdty == NULL)
1589 first_cmdty = split_cmdty;
1600 _get_sx_formula_value(creation_data->sx, template_split,
1601 &credit_num, creation_data->creation_errors,
1602 "sx-credit-formula",
"sx-credit-numeric",
1605 _get_sx_formula_value(creation_data->sx, template_split,
1606 &debit_num, creation_data->creation_errors,
1607 "sx-debit-formula",
"sx-debit-numeric", NULL);
1611 final_once = gnc_numeric_sub_fixed( debit_num, credit_num );
1614 gnc_numeric_denom(final_once),
1620 GString *err = g_string_new(
"");
1621 g_string_printf(err,
"error %d in SX [%s] final gnc_numeric value, using 0 instead",
1622 gncn_error, xaccSchedXactionGetName(creation_data->sx));
1623 g_critical(
"%s", err->str);
1624 if (creation_data->creation_errors != NULL)
1625 *creation_data->creation_errors = g_list_append(*creation_data->creation_errors, err);
1627 g_string_free(err, TRUE);
1628 final = gnc_numeric_zero();
1634 GString *err = g_string_new(
"");
1635 g_string_printf(err,
"No exchange rate available in SX [%s] for %s -> %s, value is zero",
1636 xaccSchedXactionGetName(creation_data->sx),
1639 g_critical(
"%s", err->str);
1640 if (creation_data->creation_errors != NULL)
1641 *creation_data->creation_errors = g_list_append(*creation_data->creation_errors, err);
1643 g_string_free(err, TRUE);
1644 final = gnc_numeric_zero();
1658 GList **creation_errors, gint count)
1661 Account* sx_template_account = gnc_sx_get_template_transaction_account(sx);
1663 if (!sx_template_account)
1665 g_critical(
"Huh? No template account for the SX %s", xaccSchedXactionGetName(sx));
1669 if (!xaccSchedXactionGetEnabled(sx))
1671 g_debug(
"Skipping non-enabled SX [%s]",
1672 xaccSchedXactionGetName(sx));
1676 create_cashflow_data.hash = map;
1677 create_cashflow_data.creation_errors = creation_errors;
1678 create_cashflow_data.sx = sx;
1679 create_cashflow_data.count = gnc_numeric_create(count, 1);
1684 create_cashflow_helper,
1685 &create_cashflow_data);
1691 GList **creation_errors;
1692 const GDate *range_start;
1693 const GDate *range_end;
1696 static void instantiate_cashflow_cb(gpointer data, gpointer _user_data)
1707 userdata->range_end);
1713 instantiate_cashflow_internal(sx,
1715 userdata->creation_errors,
1721 const GDate *range_start,
const GDate *range_end,
1722 GHashTable* map, GList **creation_errors)
1725 userdata.hash = map;
1726 userdata.creation_errors = creation_errors;
1727 userdata.range_start = range_start;
1728 userdata.range_end = range_end;
1731 g_list_foreach(all_sxes, instantiate_cashflow_cb, &userdata);
1738 GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
1740 &range_start, &range_end,
void xaccSplitSetValue(Split *s, gnc_numeric amt)
gint xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc, void *data)
GList * gnc_g_list_map(GList *list, GncGMapFunc fn, gpointer user_data)
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
GHashTable * gnc_g_hash_new_guid_numeric(void)
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
gint num_auto_create_no_notify_instances
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
gchar * gnc_num_dbg_to_string(gnc_numeric n)
int gnc_commodity_get_fraction(const gnc_commodity *cm)
void qof_instance_get(const QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_get.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
void gnc_sx_instance_model_change_instance_state(GncSxInstanceModel *model, GncSxInstance *instance, GncSxInstanceState new_state)
GHashTable * gnc_sx_all_instantiate_cashflow_all(GDate range_start, GDate range_end)
gnc_numeric double_to_gnc_numeric(double n, gint64 denom, gint how)
void gnc_sx_destroy_temporal_state(SXTmpStateData *stateData)
utility functions for the GnuCash UI
void xaccTransSetNotes(Transaction *trans, const char *notes)
SXTmpStateData * gnc_sx_create_temporal_state(const SchedXaction *sx)
GncSxInstanceState orig_state
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.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
GHashTable * gnc_sx_instance_get_variables_for_parser(GHashTable *instance_var_hash)
void gnc_sx_instance_model_summarize(GncSxInstanceModel *model, GncSxSummary *summary)
gboolean gnc_numeric_zero_p(gnc_numeric a)
void gnc_sx_instance_model_update_sx_instances(GncSxInstanceModel *model, SchedXaction *sx)
Account * gnc_book_get_template_root(const QofBook *book)
void gnc_sx_instance_model_effect_change(GncSxInstanceModel *model, gboolean auto_create_only, GList **created_transaction_guids, GList **creation_errors)
API for Transactions and Splits (journal entries)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
guint guid_hash_to_guint(gconstpointer ptr)
gchar * gnc_numeric_to_string(gnc_numeric n)
GDate xaccSchedXactionGetNextInstance(const SchedXaction *sx, SXTmpStateData *stateData)
Returns the next occurrence of a scheduled transaction.
void gnc_sx_summary_print(const GncSxSummary *summary)
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
void xaccTransDestroy(Transaction *trans)
gint qof_event_register_handler(QofEventHandler handler, gpointer handler_data)
Register a handler for events.
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
const char * xaccTransGetNotes(const Transaction *trans)
#define xaccAccountGetGUID(X)
convert single-entry accounts to clean double-entry
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
void gnc_sx_incr_temporal_state(const SchedXaction *sx, SXTmpStateData *stateData)
Account handling public routines.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
#define GUID_ENCODING_LENGTH
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code)
void xaccSplitScrub(Split *split)
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.
Transaction * xaccTransCloneNoKvp(const Transaction *from)
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
gint gnc_sx_get_num_occur_daterange(const SchedXaction *sx, const GDate *start_date, const GDate *end_date)
const char * xaccTransGetDescription(const Transaction *trans)
void gnc_g_list_cut(GList **list, GList *cut_point)
SXTmpStateData * gnc_sx_clone_temporal_state(SXTmpStateData *stateData)
Allocates and returns a one-by-one copy of the given temporal state.
void xaccTransSetDate(Transaction *trans, int day, int mon, int year)
void xaccTransCommitEdit(Transaction *trans)
Additional event handling code.
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
gint num_auto_create_instances
#define xaccSchedXactionGetGUID(X)
void xaccTransBeginEdit(Transaction *trans)
void gnc_sx_all_instantiate_cashflow(GList *all_sxes, const GDate *range_start, const GDate *range_end, GHashTable *map, GList **creation_errors)
GList * gnc_sx_instance_get_variables(GncSxInstance *inst)
GHashTable * variable_bindings
#define xaccTransGetGUID(X)
gboolean qof_book_is_readonly(const QofBook *book)
GncSxInstanceModel * gnc_sx_get_instances(const GDate *range_end, gboolean include_disabled)
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
GHashTable * variable_names
GncSxInstanceModel * gnc_sx_get_current_instances(void)
void gnc_sx_remove_defer_instance(SchedXaction *sx, void *deferStateData)
Removes an instance from the deferred list.
time64 gnc_time(time64 *tbuf)
get the current local time
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
const char * xaccSplitGetMemo(const Split *split)
Scheduled Transactions public handling routines.
#define GNC_EVENT_ITEM_ADDED
API for Transactions and Splits (journal entries)
#define GNC_NUMERIC_RND_MASK
bitmasks for HOW flags.
gint num_to_create_instances
SplitList * xaccTransGetSplitList(const Transaction *trans)
Commodity handling public routines.
gint guid_g_hash_table_equal(gconstpointer guid_a, gconstpointer guid_b)
void gnc_gdate_set_time64(GDate *gd, time64 time)
GList * gnc_sx_instance_model_check_variables(GncSxInstanceModel *model)
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.