示例#1
0
文件: Scrub.c 项目: CAARNICL/gnucash
void
xaccAccountScrubImbalance (Account *acc)
{
    GList *node, *splits;
    const char *str;
    gint split_count = 0, curr_split_no = 1;

    if (!acc) return;

    str = xaccAccountGetName(acc);
    str = str ? str : "(null)";
    PINFO ("Looking for imbalance in account %s \n", str);

    splits = xaccAccountGetSplitList(acc);
    split_count = g_list_length (splits);
    for (node = splits; node; node = node->next)
    {
        Split *split = node->data;
        Transaction *trans = xaccSplitGetParent(split);

        PINFO("Start processing split %d of %d",
              curr_split_no, split_count);

        xaccTransScrubCurrency(trans);

        xaccTransScrubImbalance (trans, gnc_account_get_root (acc), NULL);

        PINFO("Finished processing split %d of %d",
              curr_split_no, split_count);
        curr_split_no++;
    }
}
示例#2
0
/* Is current split a security account */
static gboolean
gtu_sr_use_security (GncTreeViewSplitReg *view)
{
    RowDepth depth;
    Account *account = NULL;
    Split *split;

    split = gnc_tree_view_split_reg_get_current_split (view);

    depth = gnc_tree_view_reg_get_selected_row_depth (view);

    if (!split)
        return TRUE;

    if (depth != SPLIT3)
        return TRUE;

    if (!account)
        account = xaccSplitGetAccount (split);

    if (!account)
        return TRUE;

    if (xaccTransUseTradingAccounts (xaccSplitGetParent (split)))
    {
        if (!gnc_commodity_is_iso (xaccAccountGetCommodity (account)))
            return TRUE;
    }

    return xaccAccountIsPriced (account);
}
示例#3
0
static void
delete_template_trans(SchedXaction *sx)
{
    GList *templ_acct_splits, *curr_split_listref;
    Split *curr_split;
    Transaction *split_trans;
    GList *templ_acct_transactions = NULL;

    templ_acct_splits
    = xaccAccountGetSplitList(sx->template_acct);

    for (curr_split_listref = templ_acct_splits;
            curr_split_listref;
            curr_split_listref = curr_split_listref->next)
    {
        curr_split = (Split *) curr_split_listref->data;
        split_trans = xaccSplitGetParent(curr_split);
        if (! (g_list_find(templ_acct_transactions, split_trans)))
        {
            templ_acct_transactions
            = g_list_prepend(templ_acct_transactions, split_trans);
        }
    }

    g_list_foreach(templ_acct_transactions,
                   sxprivTransMapDelete,
                   NULL);

    return;
}
示例#4
0
文件: Scrub.c 项目: Bob-IT/gnucash
void
xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
{
    GList *node, *splits;
    const char *str;
    const char *message = _( "Looking for orphans in account %s: %u of %u");
    guint total_splits = 0;
    guint current_split = 0;

    if (!acc) return;

    str = xaccAccountGetName (acc);
    str = str ? str : "(null)";
    PINFO ("Looking for orphans in account %s \n", str);
    splits = xaccAccountGetSplitList(acc);
    total_splits = g_list_length (splits);

    for (node = splits; node; node = node->next)
    {
        Split *split = node->data;

        if (current_split % 100 == 0)
        {
            char *progress_msg = g_strdup_printf (message, str, current_split, total_splits);
            (percentagefunc)(progress_msg, (100 * current_split) / total_splits);
            g_free (progress_msg);
        }

        TransScrubOrphansFast (xaccSplitGetParent (split),
                               gnc_account_get_root (acc));
        current_split++;
    }
    (percentagefunc)(NULL, -1.0);
}
static void
gnc_split_register_save_num_cell (BasicCell * cell,
                                  gpointer save_data,
                                  gpointer user_data)
{
    SRSaveData *sd = save_data;
    SplitRegister *reg = user_data;
    const char *value;

    g_return_if_fail (gnc_basic_cell_has_name (cell, NUM_CELL));

    value = gnc_basic_cell_get_value (cell);

    DEBUG ("NUM: %s\n", value ? value : "(null)");

    /* set per book option */
    gnc_set_num_action (sd->trans, sd->split, value, NULL);

    if (gnc_num_cell_set_last_num ((NumCell *) cell, value))
    {
        SRInfo *info = gnc_split_register_get_info (reg);
        Split *blank_split = xaccSplitLookup (&info->blank_split_guid,
                                                  gnc_get_current_book ());
        Transaction *blank_trans = xaccSplitGetParent (blank_split);

        if (sd->trans == blank_trans)
           gnc_split_register_set_last_num (reg, gnc_basic_cell_get_value (cell));
    }
}
示例#6
0
static gboolean
gncScrubLotIsSingleLotLinkSplit (GNCLot *lot)
{
    Split *split = NULL;
    Transaction *trans = NULL;

    // Lots with a single split which is also a lot link transaction split
    // may be sign of a dangling payment. Let's try to fix that

    // Only works for single split lots...
    if (1 != gnc_lot_count_splits (lot))
        return FALSE;

    split = gnc_lot_get_earliest_split (lot);
    trans = xaccSplitGetParent (split);

    if (!trans)
    {
        // Ooops - the split doesn't belong to any transaction !
        // This is not expected so issue a warning and continue with next split
        PWARN("Encountered a split in a business lot that's not part of any transaction. "
              "This is unexpected! Skipping split %p.", split);
        return FALSE;
    }

    // Only works if single split belongs to a lot link transaction...
    if (xaccTransGetTxnType (trans) != TXN_TYPE_LINK)
        return FALSE;

    return TRUE;
}
示例#7
0
gboolean
gncOwnerReduceSplitTo (Split *split, gnc_numeric target_value)
{
    gnc_numeric split_val = xaccSplitGetValue (split);
    gnc_numeric rem_val;
    Split *rem_split;
    Transaction *txn;
    GNCLot *lot;

    if (gnc_numeric_positive_p (split_val) != gnc_numeric_positive_p (target_value))
        return FALSE; // Split and target value have to be of the same sign

    if (gnc_numeric_equal (split_val, target_value))
        return FALSE; // Split already has the target value

    rem_val = gnc_numeric_sub (split_val, target_value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); // note: values are of opposite sign
    rem_split = xaccMallocSplit (xaccSplitGetBook (split));
    xaccSplitCopyOnto (split, rem_split);
    xaccSplitSetValue (rem_split, rem_val);

    txn = xaccSplitGetParent (split);
    xaccTransBeginEdit (txn);
    xaccSplitSetValue (split, target_value);
    xaccSplitSetParent (rem_split, txn);
    xaccTransCommitEdit (txn);

    lot = xaccSplitGetLot (split);
    gnc_lot_add_split (lot, rem_split);

    return TRUE;
}
示例#8
0
/* Is this split part of a multi split transaction */
gboolean
gnc_tree_util_split_reg_is_multi (Split *split)
{
    gboolean multi = FALSE;
    Split *osplit;

    if (!split)
        return FALSE;

    osplit = xaccSplitGetOtherSplit (split);

    if (osplit)
            multi = FALSE;
    else
    {
        /* For multi-split transactions and stock splits,
         * use a special value. */
        osplit = xaccTransGetSplit (xaccSplitGetParent (split), 1);

        if (osplit)
            multi = TRUE;
        else if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
            multi = TRUE;
        else
            multi = FALSE;
    }
    return multi;
}
static gint
_find_split_with_parent_txn(gconstpointer a, gconstpointer b)
{
    Split *split = (Split*)a;
    Transaction *txn = (Transaction*)b;

    return xaccSplitGetParent(split) == txn ? 0 : 1;
}
gboolean
gnc_split_register_split_needs_amount (SplitRegister *reg, Split *split)
{
    Transaction *txn = xaccSplitGetParent (split);
    Account *acc = xaccSplitGetAccount (split);

    return gnc_split_register_needs_conv_rate (reg, txn, acc);
}
示例#11
0
gboolean
gnc_tree_util_split_reg_needs_amount (GncTreeViewSplitReg *view, Split *split)
{
    Transaction *txn = xaccSplitGetParent (split);
    Account *acc = xaccSplitGetAccount (split);

    return gnc_tree_util_split_reg_needs_conv_rate (view, txn, acc);
}
示例#12
0
文件: Scrub.c 项目: Bob-IT/gnucash
void
xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
{
    GList *node, *splits;
    const char *str;
    const char *message = _( "Looking for imbalances in account %s: %u of %u");
    gint split_count = 0, curr_split_no = 0;

    if (!acc) return;

    str = xaccAccountGetName(acc);
    str = str ? str : "(null)";
    PINFO ("Looking for imbalances in account %s \n", str);

    splits = xaccAccountGetSplitList(acc);
    split_count = g_list_length (splits);
    for (node = splits; node; node = node->next)
    {
        Split *split = node->data;
        Transaction *trans = xaccSplitGetParent(split);

        PINFO("Start processing split %d of %d",
              curr_split_no + 1, split_count);

        if (curr_split_no % 100 == 0)
        {
            char *progress_msg = g_strdup_printf (message, str, curr_split_no, split_count);
            (percentagefunc)(progress_msg, (100 * curr_split_no) / split_count);
            g_free (progress_msg);
        }

        TransScrubOrphansFast (xaccSplitGetParent (split),
                               gnc_account_get_root (acc));
        (percentagefunc)(NULL, 0.0);

        xaccTransScrubCurrency(trans);

        xaccTransScrubImbalance (trans, gnc_account_get_root (acc), NULL);

        PINFO("Finished processing split %d of %d",
              curr_split_no + 1, split_count);
        curr_split_no++;
    }
    (percentagefunc)(NULL, -1.0);
}
示例#13
0
/* Used several places in a transaction edit where many other
 * parameters are also being set, so individual commits wouldn't be
 * appropriate. */
void gnc_import_set_split_online_id(Split * split,
                                    const gchar * string_value)
{
    kvp_frame * frame;
    xaccTransBeginEdit (xaccSplitGetParent (split));
    frame = xaccSplitGetSlots(split);
    kvp_frame_set_str (frame, "online_id", string_value);
    qof_instance_set_dirty (QOF_INSTANCE (split));
}
示例#14
0
gboolean
gncScrubBusinessLot (GNCLot *lot)
{
    gboolean splits_deleted = FALSE;
    gboolean dangling_payments = FALSE;
    gboolean dangling_lot_link = FALSE;
    Account *acc;
    gchar *lotname=NULL;

    if (!lot) return FALSE;
    lotname = g_strdup (gnc_lot_get_title (lot));
    ENTER ("(lot=%p) %s", lot, lotname ? lotname : "(no lotname)");

    acc = gnc_lot_get_account (lot);
    if (acc)
        xaccAccountBeginEdit(acc);

    // Scrub lot links.
    // They should only remain when two document lots are linked together
    xaccScrubMergeLotSubSplits (lot, FALSE);
    splits_deleted = gncScrubLotLinks (lot);

    // Look for dangling payments and repair if found
    dangling_lot_link = gncScrubLotIsSingleLotLinkSplit (lot);
    if (dangling_lot_link)
    {
        dangling_payments = gncScrubLotDanglingPayments (lot);
        if (dangling_payments)
            splits_deleted |= gncScrubLotLinks (lot);
        else
        {
            Split *split = gnc_lot_get_earliest_split (lot);
            Transaction *trans = xaccSplitGetParent (split);
            xaccTransDestroy (trans);
        }
    }

    // If lot is empty now, delete it
    if (0 == gnc_lot_count_splits (lot))
    {
        PINFO("All splits were removed from lot, deleting");
        gnc_lot_destroy (lot);
    }

    if (acc)
        xaccAccountCommitEdit(acc);

    LEAVE ("(lot=%s, deleted=%d, dangling lot link=%d, dangling_payments=%d)",
           lotname ? lotname : "(no lotname)", splits_deleted, dangling_lot_link,
           dangling_payments);
    g_free (lotname);

    return splits_deleted;
}
示例#15
0
gint
gncOwnerLotsSortFunc (GNCLot *lotA, GNCLot *lotB)
{
    GncInvoice *ia, *ib;
    Timespec da, db;

    ia = gncInvoiceGetInvoiceFromLot (lotA);
    ib = gncInvoiceGetInvoiceFromLot (lotB);

    if (ia)
        da = gncInvoiceGetDateDue (ia);
    else
        da = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_earliest_split (lotA)));

    if (ib)
        db = gncInvoiceGetDateDue (ib);
    else
        db = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_earliest_split (lotB)));

    return timespec_cmp (&da, &db);
}
示例#16
0
static void gnc_plugin_business_cmd_assign_payment (GtkAction *action,
        GncMainWindowActionData *mw)
{
    GncPluginBusiness *plugin_business;
    GncPluginBusinessPrivate *plugin_business_priv;
    GncPluginPage *plugin_page;
    GNCSplitReg *gsr;
    SplitRegister *reg;
    Split *split;
    Transaction *trans;
    gboolean have_owner;
    GncOwner owner;
    GncOwner *owner_p;

    g_return_if_fail (mw != NULL);
    g_return_if_fail (GNC_IS_PLUGIN_BUSINESS (mw->data));

    plugin_page = gnc_main_window_get_current_page(mw->window);

    // We continue only if the current page is a plugin page and more
    // specifically a register plugin page
    if (!GNC_IS_PLUGIN_PAGE(plugin_page)
            || !GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page))
        return;

    gsr = gnc_plugin_page_register_get_gsr(plugin_page);
    g_return_if_fail(gsr);

    reg = gnc_ledger_display_get_split_register( gsr->ledger );
    g_return_if_fail(reg);

    split = gnc_split_register_get_current_split(reg);
    g_return_if_fail(split);

    trans = xaccSplitGetParent(split);
    g_return_if_fail(trans);

    plugin_business = GNC_PLUGIN_BUSINESS (mw->data);
    plugin_business_priv = GNC_PLUGIN_BUSINESS_GET_PRIVATE (plugin_business);

    have_owner = gncOwnerGetOwnerFromTxn (trans, &owner);
    if (have_owner)
        owner_p = &owner;
    else if (gnc_ui_payment_is_customer_payment(trans))
        owner_p = plugin_business_priv->last_customer;
    else
        owner_p = plugin_business_priv->last_vendor;

    gnc_business_assign_payment (GTK_WINDOW (mw->window),
                                 trans, owner_p);
}
示例#17
0
/* Returns the value denom */
static int
gtu_sr_get_value_denom (Split *split)
{
    gnc_commodity *currency;
    int denom;

    currency = xaccTransGetCurrency (xaccSplitGetParent (split));
    denom = gnc_commodity_get_fraction (currency);
    if (denom == 0)
    {
        gnc_commodity *commodity = gnc_default_currency ();
        denom = gnc_commodity_get_fraction (commodity);
        if (denom == 0)
            denom = 100;
    }
    return denom;
}
示例#18
0
/* Return the string entry for transfer column and if multi */
const char *
gnc_tree_util_split_reg_get_transfer_entry (Split *split, gboolean *is_multi)
{
    static char *name = NULL;
    gboolean multi = FALSE;

    Split *osplit;

    if (is_multi)
        *is_multi = multi;

    if (!split)
        return NULL;

    osplit = xaccSplitGetOtherSplit (split);

    g_free (name);

    if (osplit)
        name = gnc_get_account_name_for_register (xaccSplitGetAccount (osplit));
    else
    {
        /* For multi-split transactions and stock splits,
         * use a special value. */
        osplit = xaccTransGetSplit (xaccSplitGetParent (split), 1);
        if (osplit)
        {
            name = g_strdup (SPLIT_TRANS_STR);
            multi = TRUE;
        }
        else if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
        {
            name = g_strdup (STOCK_SPLIT_STR);
            multi = TRUE;
        }
        else
            name = g_strdup ("");
    }

    if (is_multi)
        *is_multi = multi;

    return name;
}
示例#19
0
文件: Query.c 项目: fraga/gnucash
TransList *
xaccQueryGetTransactions (QofQuery * q, query_txn_match_t runtype)
{
    GList       * splits = qof_query_run(q);
    GList       * current = NULL;
    GList       * retval = NULL;
    GHashTable  * trans_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
    Transaction * trans = NULL;
    gpointer    val = NULL;
    int         count = 0;

    /* iterate over matching splits, incrementing a match-count in
     * the hash table */
    for (current = splits; current; current = current->next)
    {
        trans = xaccSplitGetParent((Split *)(current->data));

        /* don't waste time looking up unless we need the count
         * information */
        if (runtype == QUERY_TXN_MATCH_ALL)
        {
            val   = g_hash_table_lookup(trans_hash, trans);
            count = GPOINTER_TO_INT(val);
        }
        g_hash_table_insert(trans_hash, trans, GINT_TO_POINTER(count + 1));
    }

    /* now pick out the transactions that match */
    if (runtype == QUERY_TXN_MATCH_ALL)
    {
        g_hash_table_foreach(trans_hash, query_match_all_filter_func,
                             &retval);
    }
    else
    {
        g_hash_table_foreach(trans_hash, query_match_any_filter_func,
                             &retval);
    }

    g_hash_table_destroy(trans_hash);

    return retval;
}
示例#20
0
void
gncScrubBusinessSplit (Split *split)
{
    const gchar *memo = _("Please delete this transaction. Explanation at http://wiki.gnucash.org/wiki/Business_Features_Issues#Double_Posting");
    Transaction *txn;

    if (!split) return;
    ENTER ("(split=%p)", split);

    txn = xaccSplitGetParent (split);
    if (txn)
    {
        gchar txntype = xaccTransGetTxnType (txn);
        const gchar *read_only = xaccTransGetReadOnly (txn);
        gboolean is_void = xaccTransGetVoidStatus (txn);
        GNCLot *lot = xaccSplitGetLot (split);

        /* Look for transactions as a result of double posting an invoice or bill
         * Refer to https://bugzilla.gnome.org/show_bug.cgi?id=754209
         * to learn how this could have happened in the past.
         * Characteristics of such transaction are:
         * - read only
         * - not voided (to ensure read only is set by the business functions)
         * - transaction type is none (should be type invoice for proper post transactions)
         * - assigned to a lot
         */
        if ((txntype == TXN_TYPE_NONE) && read_only && !is_void && lot)
        {
            gchar *txn_date = qof_print_date (xaccTransGetDateEntered (txn));
            xaccTransClearReadOnly (txn);
            xaccSplitSetMemo (split, memo);
            gnc_lot_remove_split (lot, split);
            PWARN("Cleared double post status of transaction \"%s\", dated %s. "
                  "Please delete transaction and verify balance.",
                  xaccTransGetDescription (txn),
                  txn_date);
            g_free (txn_date);
        }

    }

    LEAVE ("(split=%p)", split);
}
示例#21
0
文件: Scrub.c 项目: CAARNICL/gnucash
void
xaccAccountScrubOrphans (Account *acc)
{
    GList *node;
    const char *str;

    if (!acc) return;

    str = xaccAccountGetName (acc);
    str = str ? str : "(null)";
    PINFO ("Looking for orphans in account %s \n", str);

    for (node = xaccAccountGetSplitList(acc); node; node = node->next)
    {
        Split *split = node->data;

        TransScrubOrphansFast (xaccSplitGetParent (split),
                               gnc_account_get_root (acc));
    }
}
示例#22
0
/* Find an existing lot link transaction in the given lot
 * Only use a lot link that already links at least two
 * documents (to avoid perpetuating the lot link proliferation
 * that happened in 2.6.0-2.6.3).
 */
static Transaction *
get_ll_transaction_from_lot (GNCLot *lot)
{
    SplitList *ls_iter;

    /* This should really only be called on a document lot */
    if (!gncInvoiceGetInvoiceFromLot (lot))
        return NULL;

    /* The given lot is a valid document lot. Now iterate over all
     * other lot links in this lot to find one more document lot.
     */
    for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
    {
        Split *ls = ls_iter->data;
        Transaction *ll_txn = xaccSplitGetParent (ls);
        SplitList *ts_iter;

        if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
            continue;

        for (ts_iter = xaccTransGetSplitList (ll_txn); ts_iter; ts_iter = ts_iter->next)
        {
            Split *ts = ts_iter->data;
            GNCLot *tslot = xaccSplitGetLot (ts);

            if (!tslot)
                continue;

            if (tslot == lot)
                continue;

            if (gncInvoiceGetInvoiceFromLot (lot))
                return ll_txn; /* Got one more document lot - mission accomplished */
        }
    }

    /* The lot doesn't have an ll_txn with the requested criteria... */
    return NULL;
}
示例#23
0
/********************************************************************\
 * gnc_reconcile_view_postpone                                      *
 *   postpone the reconcile information in the view by setting      *
 *   reconciled splits to cleared status                            *
 *                                                                  *
 * Args: view - view to commit                                      *
 * Returns: nothing                                                 *
\********************************************************************/
void
gnc_reconcile_view_postpone (GNCReconcileView *view)
{
    GtkTreeModel *model;
    GtkTreeIter   iter;
    int           num_splits;
    int           i;
    gpointer      entry = NULL;

    g_return_if_fail (view != NULL);
    g_return_if_fail (GNC_IS_RECONCILE_VIEW (view));

    if (view->reconciled == NULL)
        return;

    model = gtk_tree_view_get_model (GTK_TREE_VIEW (GNC_QUERY_VIEW (view)));
    gtk_tree_model_get_iter_first (model, &iter);

    num_splits = gnc_query_view_get_num_entries (GNC_QUERY_VIEW (view));

    gnc_suspend_gui_refresh();
    for (i = 0; i < num_splits; i++)
    {
        char recn;

        gtk_tree_model_get (model, &iter, REC_POINTER, &entry, -1);

        // Don't change splits past reconciliation date that haven't been
        // set to be reconciled
        if (gnc_difftime (view->statement_date,
              xaccTransGetDate (xaccSplitGetParent (entry))) >= 0 ||
                g_hash_table_lookup (view->reconciled, entry))
        {
            recn = g_hash_table_lookup (view->reconciled, entry) ? CREC : NREC;
            xaccSplitSetReconcile (entry, recn);
        }
        gtk_tree_model_iter_next (model, &iter);
    }
    gnc_resume_gui_refresh();
}
示例#24
0
void
xaccAccountScrubImbalance (Account *acc)
{
    GList *node;
    const char *str;

    if (!acc) return;

    str = xaccAccountGetName(acc);
    str = str ? str : "(null)";
    PINFO ("Looking for imbalance in account %s \n", str);

    for (node = xaccAccountGetSplitList(acc); node; node = node->next)
    {
        Split *split = node->data;
        Transaction *trans = xaccSplitGetParent(split);

        xaccTransScrubCurrency(trans);

        xaccTransScrubImbalance (trans, gnc_account_get_root (acc), NULL);
    }
}
示例#25
0
static void
gnc_ledger_display_set_watches (GNCLedgerDisplay *ld, GList *splits)
{
    GList *node;

    gnc_gui_component_clear_watches (ld->component_id);

    gnc_gui_component_watch_entity_type (ld->component_id,
                                         GNC_ID_ACCOUNT,
                                         QOF_EVENT_MODIFY | QOF_EVENT_DESTROY
                                         | GNC_EVENT_ITEM_CHANGED);

    for (node = splits; node; node = node->next)
    {
        Split *split = node->data;
        Transaction *trans = xaccSplitGetParent (split);

        gnc_gui_component_watch_entity (ld->component_id,
                                        xaccTransGetGUID (trans),
                                        QOF_EVENT_MODIFY);
    }
}
示例#26
0
文件: Query.c 项目: fraga/gnucash
SplitList *
xaccQueryGetSplitsUniqueTrans(QofQuery *q)
{
    GList       * splits = qof_query_run(q);
    GList       * current;
    GList       * result = NULL;
    GHashTable  * trans_hash = g_hash_table_new(g_direct_hash, g_direct_equal);

    for (current = splits; current; current = current->next)
    {
        Split *split = current->data;
        Transaction *trans = xaccSplitGetParent (split);

        if (!g_hash_table_lookup (trans_hash, trans))
        {
            g_hash_table_insert (trans_hash, trans, trans);
            result = g_list_prepend (result, split);
        }
    }

    g_hash_table_destroy (trans_hash);

    return g_list_reverse (result);
}
示例#27
0
void
gnc_split_register_load (SplitRegister *reg, GList * slist,
                         Account *default_account)
{
    SRInfo *info;
    Transaction *pending_trans;
    CursorBuffer *cursor_buffer;
    GHashTable *trans_table = NULL;
    CellBlock *cursor_header;
    CellBlock *lead_cursor;
    CellBlock *split_cursor;
    Transaction *blank_trans;
    Transaction *find_trans;
    Transaction *trans;
    CursorClass find_class;
    Split *find_trans_split;
    Split *blank_split;
    Split *find_split;
    Split *split;
    Table *table;
    GList *node;

    gboolean start_primary_color = TRUE;
    gboolean found_pending = FALSE;
    gboolean need_divider_upper = FALSE;
    gboolean found_divider_upper = FALSE;
    gboolean found_divider = FALSE;
    gboolean has_last_num = FALSE;
    gboolean multi_line;
    gboolean dynamic;
    gboolean we_own_slist = FALSE;
    gboolean use_autoreadonly = qof_book_uses_autoreadonly(gnc_get_current_book());

    VirtualCellLocation vcell_loc;
    VirtualLocation save_loc;

    int new_trans_split_row = -1;
    int new_trans_row = -1;
    int new_split_row = -1;
    time64 present, autoreadonly_time = 0;

    g_return_if_fail(reg);
    table = reg->table;
    g_return_if_fail(table);
    info = gnc_split_register_get_info (reg);
    g_return_if_fail(info);

    ENTER("reg=%p, slist=%p, default_account=%p", reg, slist, default_account);

    blank_split = xaccSplitLookup (&info->blank_split_guid,
                                   gnc_get_current_book ());

    pending_trans = xaccTransLookup (&info->pending_trans_guid,
                                     gnc_get_current_book ());

    /* make sure we have a blank split */
    if (blank_split == NULL)
    {
	/* Wouldn't it be a bug to open the new transaction if there was
	 * already a pending transaction?
	*/
	g_assert(pending_trans == NULL);
	blank_split = create_blank_split (default_account, info);
    }
    blank_trans = xaccSplitGetParent (blank_split);

    DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p",
          blank_split, blank_trans, pending_trans);

    info->default_account = *xaccAccountGetGUID (default_account);

    // gnc_table_leave_update (table, table->current_cursor_loc);

    multi_line = (reg->style == REG_STYLE_JOURNAL);
    dynamic    = (reg->style == REG_STYLE_AUTO_LEDGER);

    lead_cursor = gnc_split_register_get_passive_cursor (reg);
    split_cursor = gnc_table_layout_get_cursor (table->layout, CURSOR_SPLIT);

    /* figure out where we are going to. */
    if (info->traverse_to_new)
    {
        find_trans = blank_trans;
        find_split = NULL;
        find_trans_split = blank_split;
        find_class = CURSOR_CLASS_SPLIT;
    }
    else
    {
        find_trans = info->cursor_hint_trans;
        find_split = info->cursor_hint_split;
        find_trans_split = info->cursor_hint_trans_split;
        find_class = info->cursor_hint_cursor_class;
    }

    save_loc = table->current_cursor_loc;

    /* If the current cursor has changed we save the values for later
     * possible restoration. */
    if (gnc_table_current_cursor_changed (table, TRUE) &&
            (find_split == gnc_split_register_get_current_split (reg)))
    {
        cursor_buffer = gnc_cursor_buffer_new ();
        gnc_table_save_current_cursor (table, cursor_buffer);
    }
    else
        cursor_buffer = NULL;

    /* disable move callback -- we don't want the cascade of
     * callbacks while we are fiddling with loading the register */
    gnc_table_control_allow_move (table->control, FALSE);

    /* invalidate the cursor */
    {
        VirtualLocation virt_loc;

        gnc_virtual_location_init(&virt_loc);
        gnc_table_move_cursor_gui (table, virt_loc);
    }

    /* make sure that the header is loaded */
    vcell_loc.virt_row = 0;
    vcell_loc.virt_col = 0;
    cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
    gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
    vcell_loc.virt_row++;

    /* get the current time and reset the dividing row */
    present = gnc_time64_get_today_end ();
    if (use_autoreadonly)
    {
        GDate *d = qof_book_get_autoreadonly_gdate(gnc_get_current_book());
        // "d" is NULL if use_autoreadonly is FALSE
        autoreadonly_time = d ? timespecToTime64(gdate_to_timespec(*d)) : 0;
        g_date_free(d);
    }

    if (info->first_pass)
    {
        if (default_account)
        {
            const char *last_num = xaccAccountGetLastNum (default_account);

            if (last_num)
            {
                NumCell *cell;

                cell = (NumCell *) gnc_table_layout_get_cell(table->layout, NUM_CELL);
                gnc_num_cell_set_last_num (cell, last_num);
                has_last_num = TRUE;
            }
        }

        /* load up account names into the transfer combobox menus */
        gnc_split_register_load_xfer_cells (reg, default_account);
        gnc_split_register_load_recn_cells (reg);
        gnc_split_register_load_type_cells (reg);
    }

    if (info->separator_changed)
	change_account_separator (info, table, reg);

    table->model->dividing_row_upper = -1;
    table->model->dividing_row = -1;

    // Ensure that the transaction and splits being edited are in the split
    // list we're about to load.
    if (pending_trans != NULL)
    {
        for (node = xaccTransGetSplitList(pending_trans); node; node = node->next)
        {
            Split *pending_split = (Split*)node->data;
            if (!xaccTransStillHasSplit(pending_trans, pending_split)) continue;
            if (g_list_find(slist, pending_split) != NULL)
                continue;

            if (g_list_find_custom(slist, pending_trans,
                                   _find_split_with_parent_txn) != NULL)
                continue;

            if (!we_own_slist)
            {
                // lazy-copy
                slist = g_list_copy(slist);
                we_own_slist = TRUE;
            }
            slist = g_list_append(slist, pending_split);
        }
    }

    if (multi_line)
        trans_table = g_hash_table_new (g_direct_hash, g_direct_equal);

    /* populate the table */
    for (node = slist; node; node = node->next)
    {
        split = node->data;
        trans = xaccSplitGetParent (split);

        if (!xaccTransStillHasSplit(trans, split))
            continue;

        if (pending_trans == trans)
            found_pending = TRUE;
	/* If the transaction has only one split, and it's not our
	 * pending_trans, then it's another register's blank split and
	 * we don't want to see it.
	 */
	else if (xaccTransCountSplits (trans) == 1 &&
		 xaccSplitGetAccount (split) == NULL)
	    continue;


        /* Do not load splits from the blank transaction. */
        if (trans == blank_trans)
            continue;

        if (multi_line)
        {
            /* Skip this split if its transaction has already been loaded. */
            if (g_hash_table_lookup (trans_table, trans))
                continue;

            g_hash_table_insert (trans_table, trans, trans);
        }

        if (info->show_present_divider &&
                use_autoreadonly &&
                !found_divider_upper)
        {
            if (xaccTransGetDate (trans) >= autoreadonly_time)
            {
                table->model->dividing_row_upper = vcell_loc.virt_row;
                found_divider_upper = TRUE;
            }
            else
            {
                need_divider_upper = TRUE;
            }
        }

        if (info->show_present_divider &&
                !found_divider &&
                (xaccTransGetDate (trans) > present))
        {
            table->model->dividing_row = vcell_loc.virt_row;
            found_divider = TRUE;
        }

        /* If this is the first load of the register,
         * fill up the quickfill cells. */
        if (info->first_pass)
            add_quickfill_completions(reg->table->layout, trans, split, has_last_num);

        if (trans == find_trans)
            new_trans_row = vcell_loc.virt_row;

        if (split == find_trans_split)
            new_trans_split_row = vcell_loc.virt_row;

        gnc_split_register_add_transaction (reg, trans, split,
                                            lead_cursor, split_cursor,
                                            multi_line, start_primary_color,
                                            TRUE,
                                            find_trans, find_split, find_class,
                                            &new_split_row, &vcell_loc);

        if (!multi_line)
            start_primary_color = !start_primary_color;
    }

    if (multi_line)
        g_hash_table_destroy (trans_table);

    /* add the blank split at the end. */
    if (pending_trans == blank_trans)
        found_pending = TRUE;

    /* No upper divider yet? Store it now */
    if (info->show_present_divider &&
            use_autoreadonly &&
            !found_divider_upper && need_divider_upper)
    {
        table->model->dividing_row_upper = vcell_loc.virt_row;
        found_divider_upper = TRUE;
    }

    if (blank_trans == find_trans)
        new_trans_row = vcell_loc.virt_row;

    if (blank_split == find_trans_split)
        new_trans_split_row = vcell_loc.virt_row;

    /* If we didn't find the pending transaction, it was removed
     * from the account. */
    if (!found_pending)
    {
        info->pending_trans_guid = *guid_null ();
        if (xaccTransIsOpen (pending_trans))
            xaccTransCommitEdit (pending_trans);
        else if (pending_trans)
            g_assert_not_reached();

        pending_trans = NULL;
    }

    /* go to blank on first pass */
    if (info->first_pass)
    {
        new_split_row = -1;
        new_trans_split_row = -1;
        new_trans_row = -1;

        save_loc.vcell_loc = vcell_loc;
        save_loc.phys_row_offset = 0;
        save_loc.phys_col_offset = 0;
    }

    gnc_split_register_add_transaction (reg, blank_trans, blank_split,
                                        lead_cursor, split_cursor,
                                        multi_line, start_primary_color,
                                        info->blank_split_edited, find_trans,
                                        find_split, find_class, &new_split_row,
                                        &vcell_loc);

    /* resize the table to the sizes we just counted above */
    /* num_virt_cols is always one. */
    gnc_table_set_size (table, vcell_loc.virt_row, 1);

    /* restore the cursor to its rightful position */
    {
        VirtualLocation trans_split_loc;

        if (new_split_row > 0)
            save_loc.vcell_loc.virt_row = new_split_row;
        else if (new_trans_split_row > 0)
            save_loc.vcell_loc.virt_row = new_trans_split_row;
        else if (new_trans_row > 0)
            save_loc.vcell_loc.virt_row = new_trans_row;

        trans_split_loc = save_loc;

	gnc_split_register_get_trans_split (reg, save_loc.vcell_loc,
					    &trans_split_loc.vcell_loc);

        if (dynamic || multi_line || info->trans_expanded)
        {
            gnc_table_set_virt_cell_cursor(
                table, trans_split_loc.vcell_loc,
                gnc_split_register_get_active_cursor (reg));
            gnc_split_register_set_trans_visible (reg, trans_split_loc.vcell_loc,
                                                  TRUE, multi_line);

            info->trans_expanded = (reg->style == REG_STYLE_LEDGER);
        }
        else
        {
            save_loc = trans_split_loc;
            info->trans_expanded = FALSE;
        }

        if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
        {
            gnc_table_move_cursor_gui (table, save_loc);
            new_split_row = save_loc.vcell_loc.virt_row;

            if (find_split == gnc_split_register_get_current_split (reg))
                gnc_table_restore_current_cursor (table, cursor_buffer);
        }
    }
    gnc_cursor_buffer_destroy (cursor_buffer);
    cursor_buffer = NULL;

    update_info (info, reg);

    gnc_split_register_set_cell_fractions(
        reg, gnc_split_register_get_current_split (reg));

    gnc_table_refresh_gui (table, TRUE);

    gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc);

    /* enable callback for cursor user-driven moves */
    gnc_table_control_allow_move (table->control, TRUE);

    if (we_own_slist)
        g_list_free(slist);

    LEAVE(" ");
}
示例#28
0
文件: Scrub.c 项目: Bob-IT/gnucash
void
xaccSplitScrub (Split *split)
{
    Account *account;
    Transaction *trans;
    gnc_numeric value, amount;
    gnc_commodity *currency, *acc_commodity;
    int scu;

    if (!split) return;
    ENTER ("(split=%p)", split);

    trans = xaccSplitGetParent (split);
    if (!trans)
    {
        LEAVE("no trans");
        return;
    }

    account = xaccSplitGetAccount (split);

    /* If there's no account, this split is an orphan.
     * We need to fix that first, before proceeding.
     */
    if (!account)
    {
        xaccTransScrubOrphans (trans);
        account = xaccSplitGetAccount (split);
    }

    /* Grrr... the register gnc_split_register_load() line 203 of
     *  src/register/ledger-core/split-register-load.c will create
     * free-floating bogus transactions. Ignore these for now ...
     */
    if (!account)
    {
        PINFO ("Free Floating Transaction!");
        LEAVE ("no account");
        return;
    }

    /* Split amounts and values should be valid numbers */
    value = xaccSplitGetValue (split);
    if (gnc_numeric_check (value))
    {
        value = gnc_numeric_zero();
        xaccSplitSetValue (split, value);
    }

    amount = xaccSplitGetAmount (split);
    if (gnc_numeric_check (amount))
    {
        amount = gnc_numeric_zero();
        xaccSplitSetAmount (split, amount);
    }

    currency = xaccTransGetCurrency (trans);

    /* If the account doesn't have a commodity,
     * we should attempt to fix that first.
     */
    acc_commodity = xaccAccountGetCommodity(account);
    if (!acc_commodity)
    {
        xaccAccountScrubCommodity (account);
    }
    if (!acc_commodity || !gnc_commodity_equiv(acc_commodity, currency))
    {
        LEAVE ("(split=%p) inequiv currency", split);
        return;
    }

    scu = MIN (xaccAccountGetCommoditySCU (account),
               gnc_commodity_get_fraction (currency));

    if (gnc_numeric_same (amount, value, scu, GNC_HOW_RND_ROUND_HALF_UP))
    {
        LEAVE("(split=%p) different values", split);
        return;
    }

    /*
     * This will be hit every time you answer yes to the dialog "The
     * current transaction has changed. Would you like to record it.
     */
    PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
           " old amount %s %s, new amount %s",
           trans->description, split->memo,
           gnc_num_dbg_to_string (xaccSplitGetAmount(split)),
           gnc_commodity_get_mnemonic (currency),
           gnc_num_dbg_to_string (xaccSplitGetValue(split)));

    xaccTransBeginEdit (trans);
    xaccSplitSetAmount (split, value);
    xaccTransCommitEdit (trans);
    LEAVE ("(split=%p)", split);
}
static void
gnc_split_register_save_cells (gpointer save_data,
                               gpointer user_data)
{
    SRSaveData *sd = save_data;
    SplitRegister *reg = user_data;
    Split *other_split;
    gnc_commodity *txn_cur;
    gnc_numeric rate = gnc_numeric_zero();

    g_return_if_fail (sd != NULL);

    if (!sd->do_scrub)
        return;

    other_split = xaccSplitGetOtherSplit (sd->split);
    txn_cur = xaccTransGetCurrency (sd->trans);

    xaccSplitScrub (sd->split);

    rate = gnc_split_register_get_rate_cell (reg, RATE_CELL);

    if (other_split && !sd->reg_expanded)
    {
        gnc_numeric amount, value = xaccSplitGetValue (sd->split);
        Account *acc;
        gboolean split_needs_amount;

        split_needs_amount = gnc_split_register_split_needs_amount(reg, sd->split);

        /* We are changing the rate on the current split, but it was not
         * handled in the debcred handler, so we need to do it here.
         */
        if (!sd->handled_dc && split_needs_amount && !gnc_numeric_zero_p (rate))
        {
            gnc_numeric amount = xaccSplitGetAmount (sd->split);
            value = gnc_numeric_div(
                        amount, rate, gnc_commodity_get_fraction(txn_cur), GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetValue (sd->split, value);

            /* XXX: do we need to set the amount on the other split? */
        }

        /* Now reverse the value for the other split */
        value = gnc_numeric_neg (value);

        if (gnc_split_register_split_needs_amount (reg, other_split))
        {
            acc = xaccSplitGetAccount (other_split);

            /* If we don't have an exchange rate then figure it out.  Or, if
             * BOTH splits require an amount, then most likely we're in the
             * strange case of having a transaction currency different than
             * _both_ accounts -- so grab the other exchange rate.
             */
            if (gnc_numeric_zero_p (rate) || split_needs_amount)
                rate = xaccTransGetAccountConvRate(xaccSplitGetParent (other_split),
                                                   acc);

            amount = gnc_numeric_mul (value, rate, xaccAccountGetCommoditySCU (acc),
                                      GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetAmount (other_split, amount);

        }

        xaccSplitSetValue (other_split, value);

        xaccSplitScrub (other_split);
    }
    else if (gnc_split_register_split_needs_amount (reg, sd->split) &&
             ! gnc_numeric_zero_p (rate))
    {
        /* this is either a multi-split or expanded transaction, so only
         * deal with this split...  In particular we need to reset the
         * Value if the conv-rate changed.
         *
         * If we handled the debcred then no need to do anything there --
         * the debcred handler did all the computation.  If NOT, then the
         * convrate changed -- reset the value from the amount.
         */
        if (!sd->handled_dc)
        {
            gnc_split_register_save_amount_values (sd, reg);
#if 0
            gnc_numeric value, amount;

            amount = xaccSplitGetAmount (sd->split);
            value = gnc_numeric_div (amount, rate, gnc_commodity_get_fraction (txn_cur),
                                     GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetValue (sd->split, value);
#endif
        }
    }
}
示例#30
0
文件: policy.c 项目: CAARNICL/gnucash
static Split *
DirectionPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot, short reverse)
{
    Split *split;
    SplitList *node;
    gnc_commodity *common_currency;
    gboolean want_positive;
    gnc_numeric baln;
    Split *osplit;
    Transaction *otrans;
    Timespec open_ts;
    Account* lot_account;

    if (!pcy || !lot || !gnc_lot_get_split_list(lot)) return NULL;
    lot_account = gnc_lot_get_account(lot);
    if (!lot_account) return NULL;

    /* Recomputing the balance re-evaluates the lot closure */
    baln = gnc_lot_get_balance (lot);
    if (gnc_lot_is_closed(lot)) return NULL;

    want_positive = gnc_numeric_negative_p (baln);

    /* All splits in lot must share a common transaction currency. */
    split = gnc_lot_get_split_list(lot)->data;
    common_currency = split->parent->common_currency;

    /* Don't add a split to the lot unless it will be the new last
       split in the lot.  Otherwise our balance tests will be wrong
       and the lot may end up too thin or too fat. */
    osplit = gnc_lot_get_latest_split (lot);
    otrans = osplit ? xaccSplitGetParent (osplit) : 0;
    open_ts = xaccTransRetDatePostedTS (otrans);

    /* Walk over *all* splits in the account, till we find one that
     * hasn't been assigned to a lot.  Return that split.
     * Make use of the fact that the splits in an account are
     * already in date order; so we don't have to sort. */
    node = xaccAccountGetSplitList (lot_account);
    if (reverse)
    {
        node = g_list_last (node);
    }
    while (node)
    {
        gboolean is_match;
        gboolean is_positive;
        Timespec this_ts;
        split = node->data;
        if (split->lot) goto donext;

        /* Skip it if it's too early */
        this_ts = xaccTransRetDatePostedTS ( xaccSplitGetParent (split));
        if ((this_ts.tv_sec < open_ts.tv_sec) ||
                ((this_ts.tv_sec == open_ts.tv_sec) &&
                 (this_ts.tv_nsec < open_ts.tv_nsec)))
        {
            if (reverse)
                /* Going backwards, no point in looking further */
                break;
            goto donext;
        }

        /* Allow equiv currencies */
        is_match = gnc_commodity_equiv (common_currency,
                                        split->parent->common_currency);
        if (FALSE == is_match) goto donext;

        /* Disallow zero-amount splits in general. */
        if (gnc_numeric_zero_p(split->amount)) goto donext;

        is_positive = gnc_numeric_positive_p (split->amount);
        if ((want_positive && is_positive) ||
                ((!want_positive) && (!is_positive))) return split;
donext:
        if (reverse)
        {
            node = node->prev;
        }
        else
        {
            node = node->next;
        }
    }
    return NULL;
}