static gboolean
_get_template_split_account(GncSxInstance *instance, Split *template_split, Account **split_acct, GList **creation_errors)
{
    GncGUID *acct_guid;
    kvp_frame *split_kvpf;
    kvp_value *kvp_val;

    split_kvpf = xaccSplitGetSlots(template_split);
    /* contains the guid of the split's actual account. */
    kvp_val = kvp_frame_get_slot_path(split_kvpf,
                                      GNC_SX_ID,
                                      GNC_SX_ACCOUNT,
                                      NULL);
    if (kvp_val == NULL)
    {
        GString *err = g_string_new("");
        g_string_printf(err, "Null account kvp value for SX [%s], cancelling creation.",
                        xaccSchedXactionGetName(instance->parent->sx));
        g_critical("%s", err->str);
        if (creation_errors != NULL)
            *creation_errors = g_list_append(*creation_errors, err);
        else
            g_string_free(err, TRUE);
        return FALSE;
    }
    acct_guid = kvp_value_get_guid( kvp_val );
    *split_acct = xaccAccountLookup(acct_guid, gnc_get_current_book());
    if (*split_acct == NULL)
    {
        char guid_str[GUID_ENCODING_LENGTH+1];
        GString *err;
        guid_to_string_buff((const GncGUID*)acct_guid, guid_str);
        err = g_string_new("");
        g_string_printf(err, "Unknown account for guid [%s], cancelling SX [%s] creation.",
                        guid_str, xaccSchedXactionGetName(instance->parent->sx));
        g_critical("%s", err->str);
        if (creation_errors != NULL)
            *creation_errors = g_list_append(*creation_errors, err);
        else
            g_string_free(err, TRUE);
        return FALSE;
    }

    return TRUE;
}
static gchar*
gsidca_get_name(GncDenseCalModel *model, guint tag)
{
    GncSxInstanceDenseCalAdapter *adapter = GNC_SX_INSTANCE_DENSE_CAL_ADAPTER(model);
    GncSxInstances *insts
    = (GncSxInstances*)g_list_find_custom(adapter->instances->sx_instance_list, GUINT_TO_POINTER(tag), gsidca_find_sx_with_tag)->data;
    if (insts == NULL)
        return NULL;
    return xaccSchedXactionGetName(insts->sx);
}
static gint
_name_comparator(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
{
    gint rtn;
    GncSxListTreeModelAdapter *adapter = GNC_SX_LIST_TREE_MODEL_ADAPTER(user_data);
    GncSxInstances *a_inst, *b_inst;
    gchar *a_caseless, *b_caseless;

    a_inst = gsltma_get_sx_instances_from_orig_iter(adapter, a);
    b_inst = gsltma_get_sx_instances_from_orig_iter(adapter, b);

    if (a_inst == NULL && b_inst == NULL) return 0;
    if (a_inst == NULL) return 1;
    if (b_inst == NULL) return -1;

    a_caseless = g_utf8_casefold(xaccSchedXactionGetName(a_inst->sx), -1);
    b_caseless = g_utf8_casefold(xaccSchedXactionGetName(b_inst->sx), -1);
    rtn = g_strcmp0(a_caseless, b_caseless);
    g_free(a_caseless);
    g_free(b_caseless);

    return rtn;
}
static void
_get_sx_formula_value(GncSxInstance *instance, Split *template_split, gnc_numeric *numeric, GList **creation_errors, const char *formula_key)
{
    kvp_frame *split_kvpf;
    kvp_value *kvp_val;
    char *formula_str, *parseErrorLoc;

    split_kvpf = xaccSplitGetSlots(template_split);
    kvp_val = kvp_frame_get_slot_path(split_kvpf,
                                      GNC_SX_ID,
                                      formula_key,
                                      NULL);
    formula_str = kvp_value_get_string(kvp_val);
    if (formula_str != NULL && strlen(formula_str) != 0)
    {
        GHashTable *parser_vars = gnc_sx_instance_get_variables_for_parser(instance->variable_bindings);
        if (!gnc_exp_parser_parse_separate_vars(formula_str,
                                                numeric,
                                                &parseErrorLoc,
                                                parser_vars))
        {
            GString *err = g_string_new("");
            g_string_printf(err, "Error parsing SX [%s] key [%s]=formula [%s] at [%s]: %s",
                            xaccSchedXactionGetName(instance->parent->sx),
                            formula_key,
                            formula_str,
                            parseErrorLoc,
                            gnc_exp_parser_error_string());
            g_critical("%s", err->str);
            if (creation_errors != NULL)
                *creation_errors = g_list_append(*creation_errors, err);
            else
                g_string_free(err, TRUE);
        }

        if (parser_vars != NULL)
        {
            g_hash_table_destroy(parser_vars);
        }
    }
}
static void
gnc_plugin_page_sx_list_cmd_delete(GtkAction *action, GncPluginPageSxList *page)
{
    GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
    GtkTreeSelection *selection;
    GList *selected_paths, *to_delete = NULL;
    GtkTreeModel *model;

    selection = gtk_tree_view_get_selection(priv->tree_view);
    selected_paths = gtk_tree_selection_get_selected_rows(selection, &model);
    if (g_list_length(selected_paths) == 0)
    {
        g_warning("no selection for delete.");
        return;
    }

    to_delete = gnc_g_list_map(selected_paths,
                               (GncGMapFunc)_argument_reorder_fn,
                               priv->tree_view);
    {
        GList *list;
        for (list = to_delete; list != NULL; list = list->next)
        {
            g_debug("to-delete [%s]\n", xaccSchedXactionGetName((SchedXaction*)list->data));
        }
    }

    /* FIXME: Does this always refer to only one transaction? Or could
       multiple SXs be deleted as well? Ideally, the number of
       to-be-deleted SXs should be mentioned here; see
       dialog-sx-since-last-run.cpp:807 */
    if (gnc_verify_dialog(NULL, FALSE, "%s", _("Do you really want to delete this scheduled transaction?")))
    {
        g_list_foreach(to_delete, (GFunc)_destroy_sx, NULL);
    }

    g_list_free(to_delete);
    g_list_foreach(selected_paths, (GFunc)gtk_tree_path_free, NULL);
    g_list_free(selected_paths);
}
static void
gsslrtma_populate_tree_store(GncSxSlrTreeModelAdapter *model)
{
    GtkTreeIter sx_tree_iter;
    GList *sx_iter;
    int instances_index = -1;

    for (sx_iter = model->instances->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
    {
        GncSxInstances *instances = (GncSxInstances*)sx_iter->data;
        char last_occur_date_buf[MAX_DATE_LENGTH+1];

        {
            const GDate *last_occur = xaccSchedXactionGetLastOccurDate(instances->sx);
            if (last_occur == NULL || !g_date_valid(last_occur))
            {
                g_stpcpy(last_occur_date_buf, _("Never"));
            }
            else
            {
                qof_print_gdate(last_occur_date_buf,
                                MAX_DATE_LENGTH,
                                last_occur);
            }
        }

        if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(model->real), &sx_tree_iter, NULL, ++instances_index))
        {
            gtk_tree_store_append(model->real, &sx_tree_iter, NULL);
        }

        gtk_tree_store_set(model->real, &sx_tree_iter,
                           SLR_MODEL_COL_NAME, xaccSchedXactionGetName(instances->sx),
                           SLR_MODEL_COL_INSTANCE_STATE, NULL,
                           SLR_MODEL_COL_VARAIBLE_VALUE, NULL,
                           SLR_MODEL_COL_INSTANCE_VISIBILITY, FALSE,
                           SLR_MODEL_COL_VARIABLE_VISIBILITY, FALSE,
                           SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY, FALSE,
                           -1);

        // Insert instance information
        {
            GList *inst_iter;
            GtkTreeIter inst_tree_iter;
            char instance_date_buf[MAX_DATE_LENGTH+1];
            int instance_index = -1;

            for (inst_iter = instances->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
            {
                GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
                qof_print_gdate(instance_date_buf, MAX_DATE_LENGTH, &inst->date);

                if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(model->real), &inst_tree_iter, &sx_tree_iter, ++instance_index))
                {
                    gtk_tree_store_append(model->real, &inst_tree_iter, &sx_tree_iter);
                }
                gtk_tree_store_set(model->real, &inst_tree_iter,
                                   SLR_MODEL_COL_NAME, instance_date_buf,
                                   SLR_MODEL_COL_INSTANCE_STATE, _(gnc_sx_instance_state_names[inst->state]),
                                   SLR_MODEL_COL_VARAIBLE_VALUE, NULL,
                                   SLR_MODEL_COL_INSTANCE_VISIBILITY, TRUE,
                                   SLR_MODEL_COL_VARIABLE_VISIBILITY, FALSE,
                                   SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY, inst->state != SX_INSTANCE_STATE_CREATED,
                                   -1);

                // Insert variable information
                {
                    GList *vars = NULL, *var_iter;
                    GtkTreeIter var_tree_iter;
                    gint visible_variable_index = -1;

                    vars = gnc_sx_instance_get_variables(inst);
                    for (var_iter = vars; var_iter != NULL; var_iter = var_iter->next)
                    {
                        GncSxVariable *var = (GncSxVariable*)var_iter->data;
                        GString *tmp_str;

                        if (!var->editable)
                            continue;

                        if (gnc_numeric_check(var->value) == GNC_ERROR_OK)
                        {
                            _var_numeric_to_string(&var->value, &tmp_str);
                        }
                        else
                        {
                            tmp_str = g_string_new(_("(Need Value)"));
                        }

                        if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(model->real),
                                                           &var_tree_iter, &inst_tree_iter,
                                                           ++visible_variable_index))
                        {
                            gtk_tree_store_append(model->real, &var_tree_iter, &inst_tree_iter);
                        }
                        gtk_tree_store_set(model->real, &var_tree_iter,
                                           SLR_MODEL_COL_NAME, var->name,
                                           SLR_MODEL_COL_INSTANCE_STATE, NULL,
                                           SLR_MODEL_COL_VARAIBLE_VALUE, tmp_str->str,
                                           SLR_MODEL_COL_INSTANCE_VISIBILITY, FALSE,
                                           SLR_MODEL_COL_VARIABLE_VISIBILITY, TRUE,
                                           SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY, FALSE
                                           - 1);
                        g_string_free(tmp_str, TRUE);
                    }
                    g_list_free(vars);

                    _consume_excess_rows(model->real, visible_variable_index, &inst_tree_iter, &var_tree_iter);
                }
            }

            // if there are more instance iters, remove
            _consume_excess_rows(model->real, instance_index, &sx_tree_iter, &inst_tree_iter);
        }
    }
    _consume_excess_rows(model->real, instances_index, NULL, &sx_tree_iter);
}
static gboolean
create_each_transaction_helper(Transaction *template_txn, void *user_data)
{
    Transaction *new_txn;
    GList *txn_splits, *template_splits;
    Split *copying_split;
    gnc_commodity *first_cmdty = NULL;
    gboolean err_flag = FALSE;
    SxTxnCreationData *creation_data;

    creation_data = (SxTxnCreationData*)user_data;

    /* FIXME: In general, this should [correctly] deal with errors such
       as not finding the approrpiate Accounts and not being able to
       parse the formula|credit/debit strings. */

    new_txn = xaccTransClone(template_txn);
    xaccTransBeginEdit(new_txn);

    g_debug("creating template txn desc [%s] for sx [%s]",
            xaccTransGetDescription(new_txn),
            xaccSchedXactionGetName(creation_data->instance->parent->sx));

    /* clear any copied KVP data */
    qof_instance_set_slots(QOF_INSTANCE(new_txn), kvp_frame_new());

    /* Bug#500427: copy the notes, if any */
    if (xaccTransGetNotes(template_txn) != NULL)
    {
        xaccTransSetNotes(new_txn, g_strdup(xaccTransGetNotes(template_txn)));
    }

    xaccTransSetDate(new_txn,
                     g_date_get_day(&creation_data->instance->date),
                     g_date_get_month(&creation_data->instance->date),
                     g_date_get_year(&creation_data->instance->date));

    /* the accounts and amounts are in the kvp_frames of the splits. */
    template_splits = xaccTransGetSplitList(template_txn);
    txn_splits = xaccTransGetSplitList(new_txn);
    if ((template_splits == NULL) || (txn_splits == NULL))
    {
        g_critical("transaction w/o splits for sx [%s]",
                   xaccSchedXactionGetName(creation_data->instance->parent->sx));
        xaccTransDestroy(new_txn);
        xaccTransCommitEdit(new_txn);
        return FALSE;
    }

    for (;
            txn_splits && template_splits;
            txn_splits = txn_splits->next, template_splits = template_splits->next)
    {
        Split *template_split;
        Account *split_acct;
        gnc_commodity *split_cmdty = NULL;

        /* FIXME: Ick.  This assumes that the split lists will be ordered
           identically. :( They are, but we'd rather not have to count on
           it. --jsled */
        template_split = (Split*)template_splits->data;
        copying_split = (Split*)txn_splits->data;

        if (!_get_template_split_account(creation_data->instance, template_split, &split_acct, creation_data->creation_errors))
        {
            err_flag = TRUE;
            break;
        }

        /* clear out any copied Split frame data. */
        qof_instance_set_slots(QOF_INSTANCE(copying_split), kvp_frame_new());

        split_cmdty = xaccAccountGetCommodity(split_acct);
        if (first_cmdty == NULL)
        {
            first_cmdty = split_cmdty;
            xaccTransSetCurrency(new_txn, first_cmdty);
        }

        xaccSplitSetAccount(copying_split, split_acct);

        {
            gnc_numeric credit_num, debit_num, final;
            gint gncn_error;

            credit_num = gnc_numeric_zero();
            debit_num = gnc_numeric_zero();

            _get_credit_formula_value(creation_data->instance, template_split, &credit_num, creation_data->creation_errors);
            _get_debit_formula_value(creation_data->instance, template_split, &debit_num, creation_data->creation_errors);

            final = gnc_numeric_sub_fixed( debit_num, credit_num );

            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->instance->parent->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();
            }
Beispiel #8
0
xmlNodePtr
gnc_schedXaction_dom_tree_create(SchedXaction *sx)
{
    xmlNodePtr	ret;
    const GDate	*date;
    gint        instCount;
    const GncGUID        *templ_acc_guid;
    gboolean allow_2_2_incompat = TRUE;
    gchar *name = g_strdup (xaccSchedXactionGetName(sx));

    templ_acc_guid = xaccAccountGetGUID(sx->template_acct);

    /* FIXME: this should be the same as the def in io-gncxml-v2.c */
    ret = xmlNewNode (NULL, BAD_CAST GNC_SCHEDXACTION_TAG);

    if (allow_2_2_incompat)
        xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version2_string);
    else
        xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version_string);

    xmlAddChild( ret,
                 guid_to_dom_tree(SX_ID,
                                  xaccSchedXactionGetGUID(sx)) );

    xmlNewTextChild( ret, NULL, BAD_CAST SX_NAME, checked_char_cast (name));
    g_free (name);

    if (allow_2_2_incompat)
    {
        xmlNewTextChild( ret, NULL, BAD_CAST SX_ENABLED,
                         BAD_CAST ( sx->enabled ? "y" : "n" ) );
    }

    xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE,
                     BAD_CAST ( sx->autoCreateOption ? "y" : "n" ) );
    xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY,
                     BAD_CAST ( sx->autoCreateNotify ? "y" : "n" ) );
    xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_CREATE_DAYS,
                                     sx->advanceCreateDays));
    xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_REMIND_DAYS,
                                     sx->advanceRemindDays));

    instCount = gnc_sx_get_instance_count( sx, NULL );
    xmlAddChild( ret, int_to_dom_tree( SX_INSTANCE_COUNT,
                                       instCount ) );

    xmlAddChild( ret,
                 gdate_to_dom_tree( SX_START,
                                    xaccSchedXactionGetStartDate(sx) ) );

    date = xaccSchedXactionGetLastOccurDate(sx);
    if ( g_date_valid( date ) )
    {
        xmlAddChild( ret, gdate_to_dom_tree( SX_LAST, date ) );
    }

    if ( xaccSchedXactionHasOccurDef(sx) )
    {

        xmlAddChild(ret, int_to_dom_tree( SX_NUM_OCCUR,
                                          xaccSchedXactionGetNumOccur(sx)));
        xmlAddChild(ret, int_to_dom_tree( SX_REM_OCCUR,
                                          xaccSchedXactionGetRemOccur(sx)));

    }
    else if ( xaccSchedXactionHasEndDate(sx) )
    {
        xmlAddChild( ret,
                     gdate_to_dom_tree( SX_END,
                                        xaccSchedXactionGetEndDate(sx) ) );
    }

    /* output template account GncGUID */
    xmlAddChild( ret,
                 guid_to_dom_tree(SX_TEMPL_ACCT,
                                  templ_acc_guid));

    if (allow_2_2_incompat)
    {
        xmlNodePtr schedule_node = xmlNewNode(NULL,
                                              BAD_CAST "sx:schedule");
        GList *schedule = gnc_sx_get_schedule(sx);
        for (; schedule != NULL; schedule = schedule->next)
        {
            xmlAddChild(schedule_node, recurrence_to_dom_tree("gnc:recurrence", (Recurrence*)schedule->data));
        }
        xmlAddChild(ret, schedule_node);
    }

    /* Output deferred-instance list. */
    {
        xmlNodePtr instNode;
        SXTmpStateData *tsd;
        GList *l;

        for ( l = gnc_sx_get_defer_instances( sx ); l; l = l->next )
        {
            tsd = (SXTmpStateData*)l->data;

            instNode = xmlNewNode( NULL, BAD_CAST SX_DEFER_INSTANCE );
            if ( g_date_valid( &tsd->last_date ) )
            {
                xmlAddChild( instNode, gdate_to_dom_tree( SX_LAST,
                             &tsd->last_date ) );
            }
            xmlAddChild( instNode, int_to_dom_tree( SX_REM_OCCUR,
                                                    tsd->num_occur_rem ) );
            xmlAddChild( instNode, int_to_dom_tree( SX_INSTANCE_COUNT,
                                                    tsd->num_inst ) );
            xmlAddChild( ret, instNode );
        }
    }

    /* output kvp_frame */
    {
        xmlNodePtr kvpnode =
            kvp_frame_to_dom_tree( SX_SLOTS,
                                   xaccSchedXactionGetSlots(sx) );
        if ( kvpnode )
        {
            xmlAddChild(ret, kvpnode);
        }
    }

    return ret;
}
Beispiel #9
0
static gboolean
gnc_schedXaction_end_handler(gpointer data_for_children,
                             GSList* data_from_children, GSList* sibling_data,
                             gpointer parent_data, gpointer global_data,
                             gpointer *result, const gchar *tag)
{
    SchedXaction *sx;
    gboolean     successful = FALSE;
    xmlNodePtr   tree = (xmlNodePtr)data_for_children;
    gxpf_data    *gdata = (gxpf_data*)global_data;
    struct sx_pdata sx_pdata;

    if ( parent_data )
    {
        return TRUE;
    }

    if ( !tag )
    {
        return TRUE;
    }

    g_return_val_if_fail( tree, FALSE );

    sx = xaccSchedXactionMalloc( gdata->bookdata );

    memset(&sx_pdata, 0, sizeof(sx_pdata));
    sx_pdata.sx = sx;
    sx_pdata.book = gdata->bookdata;

    g_assert( sx_dom_handlers != NULL );

    successful = dom_tree_generic_parse( tree, sx_dom_handlers, &sx_pdata );
    if (!successful)
    {
        g_critical("failed to parse scheduled xaction");
        xmlElemDump( stdout, NULL, tree );
        gnc_sx_begin_edit( sx );
        xaccSchedXactionDestroy( sx );
        goto done;
    }

    if (tree->properties)
    {
        gchar *sx_name = xaccSchedXactionGetName(sx);
        xmlAttr *attr;
        for (attr = tree->properties; attr != NULL; attr = attr->next)
        {
            xmlChar *attr_value = attr->children->content;
            g_debug("sx attribute name[%s] value[%s]", attr->name, attr_value);
            if (strcmp((const char *)attr->name, "version") != 0)
            {
                g_warning("unknown sx attribute [%s]", attr->name);
                continue;
            }

            // if version == 1.0.0: ensure freqspec, no recurrence
            // if version == 2.0.0: ensure recurrence, no freqspec.
            if (strcmp((const char *)attr_value,
                       schedxaction_version_string) == 0)
            {
                if (!sx_pdata.saw_freqspec)
                    g_critical("did not see freqspec in version 1 sx [%s]", sx_name);
                if (sx_pdata.saw_recurrence)
                    g_warning("saw recurrence in supposedly version 1 sx [%s]", sx_name);
            }

            if (strcmp((const char *)attr_value,
                       schedxaction_version2_string) == 0)
            {
                if (sx_pdata.saw_freqspec)
                    g_warning("saw freqspec in version 2 sx [%s]", sx_name);
                if (!sx_pdata.saw_recurrence)
                    g_critical("did not find recurrence in version 2 sx [%s]", sx_name);
            }
        }
    }

    // generic_callback -> book_callback: insert the SX in the book
    gdata->cb( tag, gdata->parsedata, sx );

    /* FIXME: this should be removed somewhere near 1.8 release time. */
    if ( sx->template_acct == NULL )
    {
        Account *ra = NULL;
        const char *id = NULL;
        Account *acct = NULL;
        sixtp_gdv2 *sixdata = gdata->parsedata;
        QofBook *book;

        book = sixdata->book;

        /* We're dealing with a pre-200107<near-end-of-month> rgmerk
           change re: storing template accounts. */
        /* Fix: get account with name of our GncGUID from the template
           accounts.  Make that our template_acct pointer. */
        /* THREAD-UNSAFE */
        id = guid_to_string( xaccSchedXactionGetGUID( sx ) );
        ra = gnc_book_get_template_root(book);
        if ( ra == NULL )
        {
            g_warning( "Error getting template root account from being-parsed Book." );
            xmlFreeNode( tree );
            return FALSE;
        }
        acct = gnc_account_lookup_by_name( ra, id );
        if ( acct == NULL )
        {
            g_warning("no template account with name [%s]", id);
            xmlFreeNode( tree );
            return FALSE;
        }
        g_debug("template account name [%s] for SX with GncGUID [%s]",
                xaccAccountGetName( acct ), id );

        /* FIXME: free existing template account.
         *  HUH????? We only execute this if there isn't
         * currently an existing template account, don't we?
         * <rgmerk>
         */

        sx->template_acct = acct;
    }

done:
    xmlFreeNode( tree );

    return successful;
}