r19511 - gnucash/trunk/src/app-utils - Implement the evaluation of SX cashflow.
Christian Stimming
cstim at code.gnucash.org
Sun Aug 29 16:37:20 EDT 2010
Author: cstim
Date: 2010-08-29 16:37:20 -0400 (Sun, 29 Aug 2010)
New Revision: 19511
Trac: http://svn.gnucash.org/trac/changeset/19511
Modified:
gnucash/trunk/src/app-utils/gnc-sx-instance-model.c
Log:
Implement the evaluation of SX cashflow.
Modified: gnucash/trunk/src/app-utils/gnc-sx-instance-model.c
===================================================================
--- gnucash/trunk/src/app-utils/gnc-sx-instance-model.c 2010-08-29 20:37:05 UTC (rev 19510)
+++ gnucash/trunk/src/app-utils/gnc-sx-instance-model.c 2010-08-29 20:37:20 UTC (rev 19511)
@@ -1467,36 +1467,210 @@
}
typedef struct {
- GHashTable *hash;
- GList **creation_errors;
+ GHashTable *hash;
+ GList **creation_errors;
+ const SchedXaction *sx;
+ gnc_numeric count;
} SxCashflowData;
+static void add_to_hash_amount(GHashTable* hash, const GncGUID* guid, const gnc_numeric* amount)
+{
+ gnc_numeric* elem = g_hash_table_lookup(hash, guid);
+ if (!elem)
+ {
+ elem = g_new0(gnc_numeric, 1);
+ *elem = gnc_numeric_zero();
+ g_hash_table_insert(hash, (gpointer) guid, elem);
+ }
+ *elem = gnc_numeric_add_fixed(*elem, *amount);
+ g_debug("Adding to guid [%s] the value [%s]. Value now [%s].",
+ guid_to_string(guid),
+ gnc_num_dbg_to_string(*amount),
+ gnc_num_dbg_to_string(*elem));
+}
+
static gboolean
create_cashflow_helper(Transaction *template_txn, void *user_data)
{
-/* FIXME: Still unfinished here! */
+ SxCashflowData *creation_data = user_data;
+ GList *template_splits;
+ gboolean err_flag = FALSE;
+ const gnc_commodity *first_cmdty = NULL;
+
+ g_debug("Evaluating txn desc [%s] for sx [%s]",
+ xaccTransGetDescription(template_txn),
+ xaccSchedXactionGetName(creation_data->sx));
+
+ /* The accounts and amounts are in the kvp_frames of the
+ * splits. Hence, we iterate over all splits of this
+ * transaction. */
+ template_splits = xaccTransGetSplitList(template_txn);
+
+ if (template_splits == NULL)
+ {
+ g_critical("transaction w/o splits for sx [%s]",
+ xaccSchedXactionGetName(creation_data->sx));
+ return FALSE;
+ }
+
+ for (;
+ template_splits;
+ template_splits = template_splits->next)
+ {
+ Account *split_acct;
+ const gnc_commodity *split_cmdty = NULL;
+ const Split *template_split = (const Split*) template_splits->data;
+
+ /* Get the account that should be used for this split. */
+ if (!_get_template_split_account(creation_data->sx, template_split, &split_acct, creation_data->creation_errors))
+ {
+ g_debug("Could not find account for split");
+ err_flag = TRUE;
+ break;
+ }
+
+ /* The split's account also has some commodity */
+ split_cmdty = xaccAccountGetCommodity(split_acct);
+ if (first_cmdty == NULL)
+ {
+ first_cmdty = split_cmdty;
+ //xaccTransSetCurrency(new_txn, first_cmdty);
+ }
+
+ {
+ gnc_numeric credit_num = gnc_numeric_zero();
+ gnc_numeric debit_num = gnc_numeric_zero();
+ gnc_numeric final_once, final;
+ gint gncn_error;
+
+ /* Credit value */
+ _get_sx_formula_value(creation_data->sx, template_split, &credit_num, creation_data->creation_errors, GNC_SX_CREDIT_FORMULA, NULL);
+ /* Debit value */
+ _get_sx_formula_value(creation_data->sx, template_split, &debit_num, creation_data->creation_errors, GNC_SX_DEBIT_FORMULA, NULL);
+
+ /* The resulting cash flow number: debit minus credit,
+ * multiplied with the count factor. */
+ final_once = gnc_numeric_sub_fixed( debit_num, credit_num );
+ /* Multiply with the count factor. */
+ final = gnc_numeric_mul(final_once, creation_data->count,
+ gnc_numeric_denom(final_once),
+ GNC_HOW_RND_ROUND);
+
+ gncn_error = gnc_numeric_check(final);
+ if (gncn_error != GNC_ERROR_OK)
+ {
+ GString *err = g_string_new("");
+ g_string_printf(err, "error %d in SX [%s] final gnc_numeric value, using 0 instead",
+ gncn_error, xaccSchedXactionGetName(creation_data->sx));
+ g_critical("%s", err->str);
+ if (creation_data->creation_errors != NULL)
+ *creation_data->creation_errors = g_list_append(*creation_data->creation_errors, err);
+ else
+ g_string_free(err, TRUE);
+ final = gnc_numeric_zero();
+ }
+
+ /* Print error message if we would have needed an exchange rate */
+ if (! gnc_commodity_equal(split_cmdty, first_cmdty))
+ {
+ GString *err = g_string_new("");
+ g_string_printf(err, "No exchange rate available in SX [%s] for %s -> %s, value is zero",
+ xaccSchedXactionGetName(creation_data->sx),
+ gnc_commodity_get_mnemonic(split_cmdty),
+ gnc_commodity_get_mnemonic(first_cmdty));
+ g_critical("%s", err->str);
+ if (creation_data->creation_errors != NULL)
+ *creation_data->creation_errors = g_list_append(*creation_data->creation_errors, err);
+ else
+ g_string_free(err, TRUE);
+ final = gnc_numeric_zero();
+ }
+
+ /* And add the resulting value to the hash */
+ add_to_hash_amount(creation_data->hash, xaccAccountGetGUID(split_acct), &final);
+ }
+ }
+
return FALSE;
}
-void gnc_sx_instantiate_cashflow(const SchedXaction* sx,
- GHashTable* map, GList **creation_errors)
+static void
+instantiate_cashflow_internal(const SchedXaction* sx,
+ GHashTable* map,
+ GList **creation_errors, gint count)
{
SxCashflowData create_cashflow_data;
Account* sx_template_account = gnc_sx_get_template_transaction_account(sx);
+ if (!sx_template_account)
+ {
+ g_critical("Huh? No template account for the SX %s", xaccSchedXactionGetName(sx));
+ return;
+ }
+
create_cashflow_data.hash = map;
create_cashflow_data.creation_errors = creation_errors;
+ create_cashflow_data.sx = sx;
+ create_cashflow_data.count = gnc_numeric_create(count, 1);
+ /* The cash flow numbers are in the transactions of the template
+ * account, so run this foreach on the transactions. */
xaccAccountForEachTransaction(sx_template_account,
create_cashflow_helper,
&create_cashflow_data);
}
+void gnc_sx_instantiate_cashflow(const SchedXaction* sx,
+ GHashTable* map, GList **creation_errors)
+{
+ /* Calculate ("Instantiate") the cash flow for exactly one
+ * occurrence */
+ instantiate_cashflow_internal(sx, map, creation_errors, 1);
+}
+
+typedef struct {
+ GHashTable *hash;
+ GList **creation_errors;
+ const GDate *range_start;
+ const GDate *range_end;
+} SxAllCashflow;
+
+static void instantiate_cashflow_cb(gpointer data, gpointer _user_data)
+{
+ const SchedXaction* sx = (const SchedXaction*) data;
+ SxAllCashflow* userdata = (SxAllCashflow*) _user_data;
+ gint count;
+
+ g_assert(sx);
+ g_assert(userdata);
+
+ /* How often does this particular SX occur in the date range? */
+ count = gnc_sx_get_num_occur_daterange(sx, userdata->range_start,
+ userdata->range_end);
+ if (count > 0)
+ {
+ /* If it occurs at least once, calculate ("instantiate") its
+ * cash flow and add it to the result
+ * g_hash<GUID,gnc_numeric> */
+ instantiate_cashflow_internal(sx,
+ userdata->hash,
+ userdata->creation_errors,
+ count);
+ }
+}
+
void gnc_sx_all_instantiate_cashflow(GList *all_sxes,
const GDate *range_start, const GDate *range_end,
GHashTable* map, GList **creation_errors)
{
- /* FIXME: Still unfinished here! */
+ SxAllCashflow userdata;
+ userdata.hash = map;
+ userdata.creation_errors = creation_errors;
+ userdata.range_start = range_start;
+ userdata.range_end = range_end;
+
+ /* The work is done in the callback for each SX */
+ g_list_foreach(all_sxes, instantiate_cashflow_cb, &userdata);
}
// Local Variables:
More information about the gnucash-changes
mailing list