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(" ");
}
Example #2
0
/* Either sets the value and amount for split and returns TRUE, or
   does nothing and returns FALSE. */
static gboolean
gtu_sr_handle_exchange_rate (GncTreeViewSplitReg *view, gnc_numeric amount, Transaction *trans, Split *split, gboolean force)
{
    GncTreeModelSplitReg *model;
    XferDialog *xfer;
    gboolean rate_split_ok, rate_reg_ok;
    gnc_numeric rate_split, rate_reg, value;
    Account *reg_acc;
    gnc_commodity *xfer_comm = xaccAccountGetCommodity (xaccSplitGetAccount (split));
    gnc_commodity *reg_comm = gnc_tree_view_split_reg_get_reg_commodity (view);
    gnc_commodity *trans_curr = xaccTransGetCurrency (trans);
    gboolean expanded;
    gboolean have_rate = TRUE;

    ENTER("handle_exchange_rate amount %s, trans %p and split %p force %d", gnc_numeric_to_string (amount), trans, split, force);


    model = gnc_tree_view_split_reg_get_model_from_view (view);

    reg_acc = gnc_tree_model_split_reg_get_anchor (model);

    /* Rate from trans-curr to split-comm */
    rate_split_ok = xaccTransGetRateForCommodity (trans, xfer_comm, split, &rate_split);
    DEBUG("rate_split_ok %d and xfer_comm %s", rate_split_ok, gnc_commodity_get_fullname (xfer_comm));

    /* Rate from trans-curr to reg-comm */
    rate_reg_ok = xaccTransGetRateForCommodity (trans, reg_comm, split, &rate_reg);
    DEBUG("rate_reg_ok %d and reg_comm %s", rate_reg_ok, gnc_commodity_get_fullname (reg_comm));

    /* Are we expanded */
    expanded = gnc_tree_view_split_reg_trans_expanded (view, trans);

    if (gnc_commodity_equal (trans_curr, xfer_comm) && rate_split_ok)
    {
        xaccSplitSetAmount (split, amount);
        xaccSplitSetValue (split, amount);
        return TRUE;
    }

    if (rate_reg_ok && rate_split_ok && !force)
    {
        value = gnc_numeric_div (amount, rate_reg, gnc_commodity_get_fraction (trans_curr), GNC_HOW_DENOM_REDUCE);
        amount = gnc_numeric_mul (value, rate_split, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
    }
    else
    {
        if (!rate_split_ok)
            rate_split = gtu_sr_get_rate_from_db (reg_comm, xfer_comm);

        /* create the exchange-rate dialog */
        xfer = gnc_xfer_dialog (NULL, NULL);

        gnc_xfer_dialog_is_exchange_dialog (xfer, &rate_split);

        /* fill in the dialog entries */
        gnc_xfer_dialog_set_description (xfer, xaccTransGetDescription (trans));
        gnc_xfer_dialog_set_memo (xfer, xaccSplitGetMemo (split));

        /* Get per book option */
        gnc_xfer_dialog_set_num (xfer, gnc_get_num_action (trans, split));
        gnc_xfer_dialog_set_date (xfer, timespecToTime64 (xaccTransRetDatePostedTS (trans)));

        value = amount;
        if (gnc_xfer_dialog_run_exchange_dialog (xfer, &rate_split, value, reg_acc, trans, xfer_comm, expanded))
        {
            if (!rate_split_ok)
                rate_split = gnc_numeric_create (1, 1);
            have_rate = FALSE;
        }
        else
            have_rate = TRUE;

        amount = gnc_numeric_mul (value, rate_split, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
    }
    xaccSplitSetAmount (split, amount);
    xaccSplitSetValue (split, value);

    LEAVE("handle_exchange_rate set split %p amt=%s; and val=%s", split, gnc_numeric_to_string (amount), gnc_numeric_to_string (value));
    return have_rate;
}
Example #3
0
/**
 * @fixme Move this non-GUI code into the engine.
 **/
static void
gnc_ui_accounts_recurse (Account *parent, GList **currency_list,
                         GNCSummarybarOptions options)
{
    gnc_numeric start_amount;
    gnc_numeric start_amount_default_currency;
    gnc_numeric end_amount;
    gnc_numeric end_amount_default_currency;
    GNCAccountType account_type;
    gnc_commodity * account_currency;
    GNCCurrencyAcc *currency_accum = NULL;
    GNCCurrencyAcc *grand_total_accum = NULL;
    GNCCurrencyAcc *non_curr_accum = NULL;
    GList *children, *node;
    gboolean non_currency = FALSE;
    Timespec end_timespec;
    Timespec start_timespec;

    if (parent == NULL) return;

    children = gnc_account_get_children(parent);
    for (node = children; node; node = g_list_next(node))
    {
        Account *account = node->data;

        account_type = xaccAccountGetType(account);
        account_currency = xaccAccountGetCommodity(account);

        if (options.grand_total)
            grand_total_accum = gnc_ui_get_currency_accumulator(currency_list,
                                options.default_currency,
                                TOTAL_GRAND_TOTAL);

        if (!gnc_commodity_is_currency(account_currency))
        {
            non_currency = TRUE;
            non_curr_accum = gnc_ui_get_currency_accumulator(currency_list,
                             options.default_currency,
                             TOTAL_NON_CURR_TOTAL);
        }

        if (!non_currency || options.non_currency)
        {
            currency_accum = gnc_ui_get_currency_accumulator(currency_list,
                             account_currency,
                             TOTAL_SINGLE);
        }

        switch (account_type)
        {
        case ACCT_TYPE_BANK:
        case ACCT_TYPE_CASH:
        case ACCT_TYPE_ASSET:
        case ACCT_TYPE_STOCK:
        case ACCT_TYPE_MUTUAL:
        case ACCT_TYPE_CREDIT:
        case ACCT_TYPE_LIABILITY:
        case ACCT_TYPE_PAYABLE:
        case ACCT_TYPE_RECEIVABLE:
            end_amount = xaccAccountGetBalanceAsOfDate(account, options.end_date);
            timespecFromTime64(&end_timespec, options.end_date);
            end_amount_default_currency =
                xaccAccountConvertBalanceToCurrencyAsOfDate
                (account, end_amount, account_currency, options.default_currency,
                 timespecToTime64(timespecCanonicalDayTime(end_timespec)));

            if (!non_currency || options.non_currency)
            {
                currency_accum->assets =
                    gnc_numeric_add (currency_accum->assets, end_amount,
                                     gnc_commodity_get_fraction (account_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
            }

            if (non_currency)
            {
                non_curr_accum->assets =
                    gnc_numeric_add (non_curr_accum->assets, end_amount_default_currency,
                                     gnc_commodity_get_fraction (options.default_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
            }

            if (options.grand_total)
            {
                grand_total_accum->assets =
                    gnc_numeric_add (grand_total_accum->assets, end_amount_default_currency,
                                     gnc_commodity_get_fraction (options.default_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
            }

            gnc_ui_accounts_recurse(account, currency_list, options);
            break;
        case ACCT_TYPE_INCOME:
        case ACCT_TYPE_EXPENSE:
            start_amount = xaccAccountGetBalanceAsOfDate(account, options.start_date);
            timespecFromTime64(&start_timespec, options.start_date);
            start_amount_default_currency =
                xaccAccountConvertBalanceToCurrencyAsOfDate
                (account, start_amount, account_currency, options.default_currency,
                 timespecToTime64(timespecCanonicalDayTime(start_timespec)));
            end_amount = xaccAccountGetBalanceAsOfDate(account, options.end_date);
            timespecFromTime64(&end_timespec, options.end_date);
            end_amount_default_currency =
                xaccAccountConvertBalanceToCurrencyAsOfDate
                (account, end_amount, account_currency, options.default_currency,
                 timespecToTime64(timespecCanonicalDayTime(end_timespec)));

            if (!non_currency || options.non_currency)
            {
                currency_accum->profits =
                    gnc_numeric_add (currency_accum->profits, start_amount,
                                     gnc_commodity_get_fraction (account_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
                currency_accum->profits =
                    gnc_numeric_sub (currency_accum->profits, end_amount,
                                     gnc_commodity_get_fraction (account_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
            }

            if (non_currency)
            {
                non_curr_accum->profits =
                    gnc_numeric_add (non_curr_accum->profits, start_amount_default_currency,
                                     gnc_commodity_get_fraction (options.default_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
                non_curr_accum->profits =
                    gnc_numeric_sub (non_curr_accum->profits, end_amount_default_currency,
                                     gnc_commodity_get_fraction (options.default_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
            }

            if (options.grand_total)
            {
                grand_total_accum->profits =
                    gnc_numeric_add (grand_total_accum->profits,
                                     start_amount_default_currency,
                                     gnc_commodity_get_fraction (options.default_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
                grand_total_accum->profits =
                    gnc_numeric_sub (grand_total_accum->profits,
                                     end_amount_default_currency,
                                     gnc_commodity_get_fraction (options.default_currency),
                                     GNC_HOW_RND_ROUND_HALF_UP);
            }

            gnc_ui_accounts_recurse(account, currency_list, options);
            break;
        case ACCT_TYPE_EQUITY:
            /* no-op, see comments at top about summing assets */
            break;
            /**
             * @fixme I don't know if this is right or if trading accounts should be
             *        treated like income and expense accounts.
             **/
        case ACCT_TYPE_TRADING:
            break;
        case ACCT_TYPE_CURRENCY:
        default:
            break;
        }
    }
    g_list_free(children);
}
Example #4
0
void
gnc_payment_window_fill_docs_list (PaymentWindow *pw)
{
    GtkListStore *store;
    GList *list = NULL, *node;

    g_return_if_fail (pw->docs_list_tree_view && GTK_IS_TREE_VIEW(pw->docs_list_tree_view));

    /* Get a list of open lots for this owner and post account */
    if (pw->owner.owner.undefined)
        list = xaccAccountFindOpenLots (pw->post_acct, gncOwnerLotMatchOwnerFunc,
                                        &pw->owner, NULL);

    /* Clear the existing list */
    store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pw->docs_list_tree_view)));
    gtk_list_store_clear(store);

    /* Add the documents and overpayments to the tree view */
    for (node = list; node; node = node->next)
    {
        GNCLot *lot = node->data;
        time64 doc_date_time = 0;
        const gchar *doc_type_str = NULL;
        const gchar *doc_id_str   = NULL;
        const gchar *doc_deb_str  = NULL;
        const gchar *doc_cred_str = NULL;
        GtkTreeIter iter;
        Timespec doc_date;
        GncInvoice *document;
        gnc_numeric value = gnc_numeric_zero();
        gnc_numeric debit = gnc_numeric_zero();
        gnc_numeric credit = gnc_numeric_zero();

        /* Find the lot's document if it exists,
         * it could also be a prepayment lot. */
        document = gncInvoiceGetInvoiceFromLot (lot);

        /* Find the document's date or pre-payment date */
        if (document)
            doc_date = gncInvoiceGetDatePosted (document);
        else
        {
            /* Calculate the payment date based on the lot splits */
            Transaction *trans = xaccSplitGetParent (gnc_lot_get_latest_split (lot));
            if (trans)
                doc_date = xaccTransRetDatePostedTS (trans);
            else
                continue; /* No valid split in this lot, skip it */
        }
        doc_date_time = timespecToTime64 (doc_date);

        /* Find the document type. No type means pre-payment in this case */
        if (document)
        {
            doc_type_str = gncInvoiceGetTypeString (document);
        }
        else
            doc_type_str = _("Pre-Payment");

        /* Find the document id. Empty for pre-payments. */
        if (document)
        {
            doc_id_str = gncInvoiceGetID (document);
        }

        /* Find the debit/credit amount.
         * Invoices/vendor credit notes are debit (increasing the balance)
         * Customer credit notes/bills are credit (decreasing the balance)
         * Pre-payments are debit or credit depending on their sign
         */
        value = gnc_lot_get_balance (lot);

        if (gnc_numeric_positive_p (value))
            debit = value;
        else
            credit = gnc_numeric_neg (value);

        /* Only display non-zero debits/credits */
        if (!gnc_numeric_zero_p (debit))
            doc_deb_str = xaccPrintAmount (debit, gnc_default_print_info (FALSE));
        if (!gnc_numeric_zero_p (credit))
            doc_cred_str = xaccPrintAmount (credit, gnc_default_print_info (FALSE));

        gtk_list_store_append (store, &iter);
        gtk_list_store_set (store, &iter,
                            0, doc_date_time,
                            1, doc_id_str,
                            2, doc_type_str,
                            3, doc_deb_str,
                            4, doc_cred_str,
                            5, (gpointer)lot,
                            -1);

    }

    g_list_free (list);

    /* Highlight the preset invoice if it's in the new list */
    gnc_payment_dialog_highlight_document (pw);
}
Example #5
0
static void
gncOwnerCreateLotLink (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
{
    const gchar *action = _("Lot Link");
    Account *acct = gnc_lot_get_account (from_lot);
    const gchar *name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
    Transaction *ll_txn = NULL;
    gnc_numeric from_lot_bal, to_lot_bal;
    Timespec from_ts, to_ts;
    time64 time_posted;
    Split *split;

    /* Sanity check */
    if (!gncInvoiceGetInvoiceFromLot (from_lot) ||
        !gncInvoiceGetInvoiceFromLot (to_lot))
        return;

    /* Determine transaction date based on lot splits */
    from_ts = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (from_lot)));
    to_ts   = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (to_lot)));
    if (timespecToTime64 (from_ts) >= timespecToTime64 (to_ts))
        time_posted = timespecToTime64 (from_ts);
    else
        time_posted = timespecToTime64 (to_ts);

    /* Figure out how much we can offset between the lots */
    from_lot_bal = gnc_lot_get_balance (from_lot);
    to_lot_bal = gnc_lot_get_balance (to_lot);
    if (gnc_numeric_compare (gnc_numeric_abs (from_lot_bal),
                             gnc_numeric_abs (to_lot_bal)) > 0)
        from_lot_bal = gnc_numeric_neg (to_lot_bal);
    else
        to_lot_bal = gnc_numeric_neg (from_lot_bal);

    xaccAccountBeginEdit (acct);

    /* Look for a pre-existing lot link we can extend */
    ll_txn = get_ll_transaction_from_lot (from_lot);

    if (!ll_txn)
        ll_txn = get_ll_transaction_from_lot (to_lot);

    if (!ll_txn)
    {
        /* No pre-existing lot link. Create one. */
        Timespec ts;

        timespecFromTime64 (&ts, time_posted);

        ll_txn = xaccMallocTransaction (gnc_lot_get_book (from_lot));
        xaccTransBeginEdit (ll_txn);

        xaccTransSetDescription (ll_txn, name ? name : "(Unknown)");
        xaccTransSetCurrency (ll_txn, xaccAccountGetCommodity(acct));
        xaccTransSetDateEnteredSecs (ll_txn, gnc_time (NULL));
        xaccTransSetDatePostedTS (ll_txn, &ts);
        xaccTransSetTxnType (ll_txn, TXN_TYPE_LINK);
    }
    else
    {
        Timespec ts = xaccTransRetDatePostedTS (ll_txn);
        xaccTransBeginEdit (ll_txn);

        /* Maybe we need to update the post date of the transaction ? */
        if (time_posted > timespecToTime64 (ts))
        {
            timespecFromTime64 (&ts, time_posted);
            xaccTransSetDatePostedTS (ll_txn, &ts);

        }
    }

    /* Create a split for the from_lot */
    split = xaccMallocSplit (gnc_lot_get_book (from_lot));
    /* set Action using utility function */
    gnc_set_num_action (NULL, split, NULL, action);
    xaccAccountInsertSplit (acct, split);
    xaccTransAppendSplit (ll_txn, split);
    /* To offset the lot balance, the split must be of the opposite sign */
    xaccSplitSetBaseValue (split, gnc_numeric_neg (from_lot_bal), xaccAccountGetCommodity(acct));
    gnc_lot_add_split (from_lot, split);

    /* Create a split for the to_lot */
    split = xaccMallocSplit (gnc_lot_get_book (to_lot));
    /* set Action using utility function */
    gnc_set_num_action (NULL, split, NULL, action);
    xaccAccountInsertSplit (acct, split);
    xaccTransAppendSplit (ll_txn, split);
    /* To offset the lot balance, the split must be of the opposite sign */
    xaccSplitSetBaseValue (split, gnc_numeric_neg (to_lot_bal), xaccAccountGetCommodity(acct));
    gnc_lot_add_split (to_lot, split);

    xaccTransCommitEdit (ll_txn);


    /* Do some post-cleaning on the lots
     * The above actions may have created splits that are
     * in the same transaction and lot. These can be merged.
     */
    xaccScrubMergeLotSubSplits (to_lot, FALSE);
    xaccScrubMergeLotSubSplits (from_lot, FALSE);
    /* And finally set the same memo for all remaining splits
     * It's a convenience for the users to identify all documents
     * involved in the link.
     */
    gncOwnerSetLotLinkMemo (ll_txn);
    xaccAccountCommitEdit (acct);
}