示例#1
0
static void
gnc_invoice_select_search_set_label(GncISI* isi)
{
    GncOwnerType owner_type;
    char *label;

    g_assert(isi);
    if (!isi->label) return;

    owner_type = gncOwnerGetType(gncOwnerGetEndOwner(&isi->owner));

    /* Translators:  See comments in dialog-invoice.c:gnc_invoice_search() */
    switch (owner_type)
    {
    case GNC_OWNER_VENDOR:
        label = _("Bill");
        break;
    case GNC_OWNER_EMPLOYEE:
        label = _("Voucher");
        break;
    default:
        label = _("Invoice");
        break;
    }

    gtk_label_set_text(GTK_LABEL(isi->label), label);
}
示例#2
0
static void load_payment_type_cells (GncEntryLedger *ledger)
{
    ComboCell *cell;
    const GncOwner *owner;
    GncEmployee *employee;

    cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
            ENTRY_PAYMENT_CELL);
    if (!cell) return;

    if (!ledger->invoice) return;

    owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
    if (gncOwnerGetType (owner) != GNC_OWNER_EMPLOYEE)
        return;

    employee = gncOwnerGetEmployee (owner);
    g_return_if_fail (employee);

    gnc_combo_cell_clear_menu (cell);
    gnc_combo_cell_add_menu_item (cell, _("Cash"));

    if (gncEmployeeGetCCard (employee))
        gnc_combo_cell_add_menu_item (cell, _("Charge"));
}
示例#3
0
gboolean
gncOwnerLotMatchOwnerFunc (GNCLot *lot, gpointer user_data)
{
    const GncOwner *req_owner = user_data;
    GncOwner lot_owner;
    const GncOwner *end_owner;
    GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);

    /* Determine the owner associated to the lot */
    if (invoice)
        /* Invoice lots */
        end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
    else if (gncOwnerGetOwnerFromLot (lot, &lot_owner))
        /* Pre-payment lots */
        end_owner = gncOwnerGetEndOwner (&lot_owner);
    else
        return FALSE;

    /* Is this a lot for the requested owner ? */
    return gncOwnerEqual (end_owner, req_owner);
}
示例#4
0
PaymentWindow *
gnc_ui_payment_new_with_invoice (const GncOwner *owner, QofBook *book,
                                 GncInvoice *invoice)
{
    GncOwner owner_def;

    if (!book) return NULL;
    if (owner)
    {
        /* Figure out the company */
        gncOwnerCopy (gncOwnerGetEndOwner (owner), &owner_def);
    }
    else
    {
        gncOwnerInitCustomer (&owner_def, NULL);
    }

    return new_payment_window (&owner_def, book, invoice);
}
示例#5
0
/* XXX This code is a cut-n-paste job from the SplitRegister code;
 * the split-register should be generalized to the point where a cut-n-paste
 * like this isn't required, and this should be trashed.
 */
void gnc_entry_ledger_load (GncEntryLedger *ledger, GList *entry_list)
{
    GncEntry *blank_entry, *find_entry;
    CursorBuffer *cursor_buffer;
    Table *table;

    GList *node;
    CellBlock *cursor_header, *cursor;
    VirtualCellLocation vcell_loc;
    VirtualLocation save_loc;
    gboolean start_primary_color = TRUE;

    int new_entry_row = -1;

    if (!ledger) return;

    /* Load up cells */
    load_discount_type_cells (ledger);
    load_discount_how_cells (ledger);
    gnc_entry_ledger_load_xfer_cells (ledger);

    blank_entry = gnc_entry_ledger_get_blank_entry (ledger);

    if (blank_entry == NULL && ledger->invoice == NULL && entry_list == NULL)
        return;

    if (blank_entry == NULL && ledger->invoice)
    {
        switch (ledger->type)
        {
        case GNCENTRY_ORDER_ENTRY:
        case GNCENTRY_INVOICE_ENTRY:
        case GNCENTRY_BILL_ENTRY:
        case GNCENTRY_EXPVOUCHER_ENTRY:
        case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
        case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
        case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:

            gnc_suspend_gui_refresh ();

            blank_entry = gncEntryCreate (ledger->book);
            gncEntrySetDateGDate (blank_entry, &ledger->last_date_entered);
            ledger->blank_entry_guid = *gncEntryGetGUID (blank_entry);

            gnc_resume_gui_refresh ();

            /* The rest of this does not apply to expense vouchers */
            if (ledger->type != GNCENTRY_EXPVOUCHER_ENTRY)
            {
                const GncOwner *owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
                GncTaxTable *table = NULL;
                GncTaxIncluded taxincluded_p = GNC_TAXINCLUDED_USEGLOBAL;
                gboolean taxincluded = FALSE;
                gnc_numeric discount = gnc_numeric_zero ();
                gnc_numeric price = gnc_numeric_zero ();

                /* Determine the Price from Customer's or Vendor's Job */
                switch (gncOwnerGetType (gncInvoiceGetOwner (ledger->invoice)))
                {
                case GNC_OWNER_JOB:
                    price = gncJobGetRate( gncOwnerGetJob (gncInvoiceGetOwner (ledger->invoice)));
                    break;
                default:
                    break;
                }

                /* Determine the TaxIncluded and Discount values */
                switch (gncOwnerGetType (owner))
                {
                case GNC_OWNER_CUSTOMER:
                    taxincluded_p = gncCustomerGetTaxIncluded (owner->owner.customer);
                    discount = gncCustomerGetDiscount (owner->owner.customer);
                    break;
                case GNC_OWNER_VENDOR:
                    taxincluded_p = gncVendorGetTaxIncluded (owner->owner.vendor);
                    break;
                default:
                    break;
                }

                /* Compute the default taxincluded */
                switch (taxincluded_p)
                {
                case GNC_TAXINCLUDED_YES:
                    taxincluded = TRUE;
                    break;
                case GNC_TAXINCLUDED_NO:
                    taxincluded = FALSE;
                    break;
                case GNC_TAXINCLUDED_USEGLOBAL:
                    if (ledger->prefs_group)
                    {
                        taxincluded = gnc_prefs_get_bool (ledger->prefs_group, GNC_PREF_TAX_INCL);
                    }
                    else
                    {
                        taxincluded = FALSE;
                    }
                    break;
                }

                /* Compute the proper taxtable */
                switch (gncOwnerGetType (owner))
                {
                case GNC_OWNER_CUSTOMER:
                    table = gnc_business_get_default_tax_table (ledger->book,
                            GNC_OWNER_CUSTOMER);

                    if (gncCustomerGetTaxTableOverride (owner->owner.customer))
                        table = gncCustomerGetTaxTable (owner->owner.customer);
                    break;

                case GNC_OWNER_VENDOR:
                    table = gnc_business_get_default_tax_table (ledger->book,
                            GNC_OWNER_VENDOR);

                    if (gncVendorGetTaxTableOverride (owner->owner.vendor))
                        table = gncVendorGetTaxTable (owner->owner.vendor);
                    break;

                default:
                    break;
                }

                if (ledger->is_cust_doc)
                {
                    gncEntrySetInvTaxTable (blank_entry, table);
                    gncEntrySetInvTaxIncluded (blank_entry, taxincluded);
                    gncEntrySetInvDiscount (blank_entry, discount);
                    gncEntrySetInvPrice (blank_entry, price);
                }
                else
                {
                    gncEntrySetBillTaxTable (blank_entry, table);
                    gncEntrySetBillTaxIncluded (blank_entry, taxincluded);
                    gncEntrySetBillPrice (blank_entry, price);
                }
            }

            break;
        default:
            ledger->blank_entry_guid = *guid_null ();
            break;
        }
        ledger->blank_entry_edited = FALSE;
    }

    table = ledger->table;

    gnc_table_leave_update (table, table->current_cursor_loc);
    save_loc = table->current_cursor_loc;

    /* Figure out where we are going to */
    if (ledger->traverse_to_new)
    {
        find_entry = blank_entry;
    }
    else if (ledger->hint_entry)
    {
        find_entry = ledger->hint_entry;
    }
    else
    {
        find_entry = gnc_entry_ledger_get_current_entry(ledger);
        /* XXX: get current entry (cursor_hint_xxx) */
    }

    /* If the current cursor has changed we save the values for later
     * possible restoration. */
    if (gnc_table_current_cursor_changed (table, TRUE) &&
            (find_entry == gnc_entry_ledger_get_current_entry (ledger)))
    {
        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;

        virt_loc.vcell_loc.virt_row = -1;
        virt_loc.vcell_loc.virt_col = -1;
        virt_loc.phys_row_offset = -1;
        virt_loc.phys_col_offset = -1;

        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 */
    table->model->dividing_row_upper = -1;
    table->model->dividing_row = -1;
    table->model->dividing_row_lower = -1;
    cursor = gnc_table_layout_get_cursor (table->layout, "cursor");

    /* Populate the table */
    for (node = entry_list; node; node = node->next)
    {
        GncEntry *entry = node->data;

        /* Don't load the blank entry */
        if (entry == blank_entry)
            continue;

        /* If this is the first load of the ledger, fill the quickfill cells */
        {
            /* XXX */
        }

        if (entry == find_entry)
            new_entry_row = vcell_loc.virt_row;

        gnc_table_set_vcell (table, cursor, gncEntryGetGUID (entry),
                             TRUE, start_primary_color, vcell_loc);
        vcell_loc.virt_row++;

        /* Flip color for the next guy */
        start_primary_color = !start_primary_color;
    }

    /* Add the blank entry at the end. */
    if (blank_entry)
    {
        gnc_table_set_vcell (table, cursor, gncEntryGetGUID (blank_entry),
                             TRUE, start_primary_color, vcell_loc);

        if (find_entry == blank_entry)
            new_entry_row = vcell_loc.virt_row;

        vcell_loc.virt_row++;
    }

    /* Resize the table */
    gnc_table_set_size (table, vcell_loc.virt_row, 1);

    /* Restore the cursor to its rightful position */
    if (new_entry_row > 0)
        save_loc.vcell_loc.virt_row = new_entry_row;

    if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
    {
        gnc_table_move_cursor_gui (table, save_loc);

        if (find_entry == gnc_entry_ledger_get_current_entry (ledger))
            gnc_table_restore_current_cursor (table, cursor_buffer);
    }

    gnc_cursor_buffer_destroy (cursor_buffer);
    cursor_buffer = NULL;

    /* Reset the ledger */
    ledger->traverse_to_new = FALSE;
    ledger->hint_entry = NULL;

    /* Set the cell fractions */


    gnc_table_refresh_gui (table, TRUE);
    gnc_entry_ledger_show_entry (ledger, table->current_cursor_loc.vcell_loc);

    /* Set completion character */
    gnc_combo_cell_set_complete_char
    ((ComboCell *)
     gnc_table_layout_get_cell (table->layout, ENTRY_IACCT_CELL),
     gnc_get_account_separator ());

    gnc_combo_cell_set_complete_char
    ((ComboCell *)
     gnc_table_layout_get_cell (table->layout, ENTRY_BACCT_CELL),
     gnc_get_account_separator ());

    /* enable callback for cursor user-driven moves */
    gnc_table_control_allow_move (table->control, TRUE);
}
示例#6
0
void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots)
{
    GList *base_iter;

    /* General note: in the code below the term "payment" can
     * both mean a true payment or a document of
     * the opposite sign (invoice vs credit note) relative to
     * the lot being processed. In general this function will
     * perform a balancing action on a set of lots, so you
     * will also find frequent references to balancing instead. */

    /* Payments can only be applied when at least an owner
     * and a list of lots to use are given */
    if (!owner) return;
    if (!lots) return;

    for (base_iter = lots; base_iter; base_iter = base_iter->next)
    {
        GNCLot *base_lot = base_iter->data;
        QofBook *book;
        Account *acct;
        const gchar *name;
        GList *lot_list, *lot_iter;
        Transaction *txn = NULL;
        gnc_numeric base_lot_bal, val_to_pay, val_paid = { 0, 1 };
        gboolean base_bal_is_pos;
        const gchar *action, *memo;

        /* Only attempt to apply payments to open lots.
         * Note that due to the iterative nature of this function lots
         * in the list may become closed before they are evaluated as
         * base lot, so we should check this for each lot. */
        base_lot_bal = gnc_lot_get_balance (base_lot);
        if (gnc_numeric_zero_p (base_lot_bal))
            continue;

        book = gnc_lot_get_book (base_lot);
        acct = gnc_lot_get_account (base_lot);
        name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
        lot_list = base_iter->next;

        /* Strings used when creating splits later on. */
        action = _("Lot Link");
        memo   = _("Internal link between invoice and payment lots");

        /* Note: to balance the lot the payment to assign
         * must have the opposite sign of the existing lot balance */
        val_to_pay = gnc_numeric_neg (base_lot_bal);
        base_bal_is_pos = gnc_numeric_positive_p (base_lot_bal);


        /* Create splits in a linking transaction between lots until
         * - either the invoice lot is balanced
         * - or there are no more balancing lots.
         */
        for (lot_iter = lot_list; lot_iter; lot_iter = lot_iter->next)
        {
            gnc_numeric payment_lot_balance;
            Split *split;
            Account *bal_acct;
            gnc_numeric  split_amt;

            GNCLot *balancing_lot = lot_iter->data;

            /* Only attempt to use open lots to balance the base lot.
             * Note that due to the iterative nature of this function lots
             * in the list may become closed before they are evaluated as
             * base lot, so we should check this for each lot. */
            if (gnc_lot_is_closed (balancing_lot))
                continue;

            /* Balancing transactions for invoice/payments can only happen
             * in the same account. */
            bal_acct = gnc_lot_get_account (balancing_lot);
            if (acct != bal_acct)
                continue;

            payment_lot_balance = gnc_lot_get_balance (balancing_lot);

            /* Only attempt to balance if the base lot and balancing lot are
             * of the opposite sign. (Otherwise we would increase the balance
             * of the lot - Duh */
            if (base_bal_is_pos == gnc_numeric_positive_p (payment_lot_balance))
                continue;

            /*
             * If there is less to pay than there's open in the lot; we're done -- apply the base_lot_vale.
             * Note that payment_value and balance are opposite in sign, so we have to compare absolute values here
             *
             * Otherwise, apply the balance, subtract that from the payment_value,
             * and move on to the next one.
             */
            if (gnc_numeric_compare (gnc_numeric_abs (val_to_pay), gnc_numeric_abs (payment_lot_balance)) <= 0)
            {
                /* abs(val_to_pay) <= abs(balance) */
                split_amt = val_to_pay;
            }
            else
            {
                /* abs(val_to_pay) > abs(balance)
                 * Remember payment_value and balance are opposite in sign,
                 * and we want a payment to neutralize the current balance
                 * so we need to negate here */
                split_amt = payment_lot_balance;
            }

            /* If not created yet, create a new transaction linking
             * the base lot and the balancing lot(s) */
            if (!txn)
            {
                Timespec ts = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (base_lot)));

                xaccAccountBeginEdit (acct);

                txn = xaccMallocTransaction (book);
                xaccTransBeginEdit (txn);

                xaccTransSetDescription (txn, name ? name : "");
                xaccTransSetCurrency (txn, xaccAccountGetCommodity(acct));
                xaccTransSetDateEnteredSecs (txn, gnc_time (NULL));
                xaccTransSetDatePostedTS (txn, &ts);
                xaccTransSetTxnType (txn, TXN_TYPE_LINK);
            }

            /* Create the split for this link in current balancing lot */
            split = xaccMallocSplit (book);
            xaccSplitSetMemo (split, memo);
            /* set Action using utility function */
            gnc_set_num_action (NULL, split, NULL, action);
            xaccAccountInsertSplit (acct, split);
            xaccTransAppendSplit (txn, split);
            xaccSplitSetBaseValue (split, gnc_numeric_neg (split_amt), xaccAccountGetCommodity(acct));
            gnc_lot_add_split (balancing_lot, split);

            /* If the balancing lot was linked to a document (invoice/credit note),
             * send an event for it as well so it gets potentially updated as paid */
            {
                GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(balancing_lot);
                if (this_invoice)
                    qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
            }

            val_paid   = gnc_numeric_add (val_paid, split_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
            val_to_pay = gnc_numeric_sub (val_to_pay, split_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
            if (gnc_numeric_zero_p (val_to_pay))
                break;
        }


        /* If the above loop managed to create a transaction and some balancing splits,
         * create the final split for the link transaction in the base lot */
        if (txn)
        {
            GncInvoice *this_invoice;
            Split *split = xaccMallocSplit (book);

            xaccSplitSetMemo (split, memo);
            /* set Action with utiltity function */
            gnc_set_num_action (NULL, split, NULL, action);
            xaccAccountInsertSplit (acct, split);
            xaccTransAppendSplit (txn, split);
            xaccSplitSetBaseValue (split, val_paid, xaccAccountGetCommodity(acct));
            gnc_lot_add_split (base_lot, split);

            xaccTransCommitEdit (txn);
            xaccAccountCommitEdit (acct);

            /* If the base lot was linked to a document (invoice/credit note),
             * send an event for it as well so it gets potentially updated as paid */
            this_invoice = gncInvoiceGetInvoiceFromLot(base_lot);
            if (this_invoice)
                qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);

        }

    }
}
示例#7
0
GNCLot *
gncOwnerCreatePaymentLot (const GncOwner *owner, Transaction *txn,
                          Account *posted_acc, Account *xfer_acc,
                          gnc_numeric amount, gnc_numeric exch, Timespec date,
                          const char *memo, const char *num)
{
    QofBook *book;
    Split *split;
    const char *name;
    gnc_commodity *commodity;
    Split *xfer_split = NULL;
    GNCLot *payment_lot;

    /* Verify our arguments */
    if (!owner || !posted_acc || !xfer_acc) return NULL;
    g_return_val_if_fail (owner->owner.undefined != NULL, NULL);

    /* Compute the ancillary data */
    book = gnc_account_get_book (posted_acc);
    name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
    commodity = gncOwnerGetCurrency (owner);
//    reverse = use_reversed_payment_amounts(owner);

    if (txn)
    {
        /* Pre-existing transaction was specified. We completely clear it,
         * except for the split in the transfer account, unless the
         * transaction can't be reused (wrong currency, wrong transfer account).
         * In that case, the transaction is simply removed and an new
         * one created. */

        xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);

        if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
        {
            g_message("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction.");
            xfer_split = NULL;
        }

        if (!xfer_split)
        {
            g_message("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one.");

            xaccTransBeginEdit (txn);
            xaccTransDestroy (txn);
            xaccTransCommitEdit (txn);

            txn = NULL;
        }
        else
        {
            int i = 0;
            xaccTransBeginEdit (txn);
            while (i < xaccTransCountSplits(txn))
            {
                Split *split = xaccTransGetSplit (txn, i);
                if (split == xfer_split)
                {
                    gnc_set_num_action (NULL, split, num, _("Payment"));
                    ++i;
                }
                else
                {
                    xaccSplitDestroy(split);
                }
            }
            /* Note: don't commit transaction now - that would insert an imbalance split.*/
        }
    }

    /* Create the transaction if we don't have one yet */
    if (!txn)
    {
        txn = xaccMallocTransaction (book);
        xaccTransBeginEdit (txn);
    }

    /* Insert a split for the transfer account if we don't have one yet */
    if (!xfer_split)
    {

        /* Set up the transaction */
        xaccTransSetDescription (txn, name ? name : "");
        /* set per book option */
        xaccTransSetCurrency (txn, commodity);
        xaccTransSetDateEnteredSecs (txn, gnc_time (NULL));
        xaccTransSetDatePostedTS (txn, &date);


        /* The split for the transfer account */
        split = xaccMallocSplit (book);
        xaccSplitSetMemo (split, memo);
        /* set per book option */
        gnc_set_num_action (NULL, split, num, _("Payment"));
        xaccAccountBeginEdit (xfer_acc);
        xaccAccountInsertSplit (xfer_acc, split);
        xaccAccountCommitEdit (xfer_acc);
        xaccTransAppendSplit (txn, split);

        if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
        {
            xaccSplitSetBaseValue (split, amount, commodity);
        }
        else
        {
            /* Need to value the payment in terms of the owner commodity */
            gnc_numeric payment_value = gnc_numeric_mul(amount,
                                        exch, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);

            xaccSplitSetAmount(split, amount);
            xaccSplitSetValue(split, payment_value);
        }
    }

    /* Add a split in the post account */
    split = xaccMallocSplit (book);
    xaccSplitSetMemo (split, memo);
    /* set per book option */
    gnc_set_num_action (NULL, split, num, _("Payment"));
    xaccAccountBeginEdit (posted_acc);
    xaccAccountInsertSplit (posted_acc, split);
    xaccAccountCommitEdit (posted_acc);
    xaccTransAppendSplit (txn, split);
    xaccSplitSetBaseValue (split, gnc_numeric_neg (amount), commodity);

    /* Create a new lot for the payment */
    payment_lot = gnc_lot_new (book);
    gncOwnerAttachToLot (owner, payment_lot);
    gnc_lot_add_split (payment_lot, split);

    /* Mark the transaction as a payment */
    gnc_set_num_action (txn, NULL, num, _("Payment"));
    xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);

    /* Commit this new transaction */
    xaccTransCommitEdit (txn);

    return payment_lot;
}
示例#8
0
const GncGUID * gncOwnerGetEndGUID (const GncOwner *owner)
{
    if (!owner) return NULL;
    return gncOwnerGetGUID (gncOwnerGetEndOwner (owner));
}
示例#9
0
static void
gnc_entry_ledger_set_watches (GncEntryLedger *ledger, GList *entries)
{
    GList *node;
    QofIdType type = NULL;

    gnc_gui_component_clear_watches (ledger->component_id);

    switch (ledger->type)
    {
    case GNCENTRY_ORDER_ENTRY:
    case GNCENTRY_ORDER_VIEWER:
        type = GNC_ORDER_MODULE_NAME;
        break;

    case GNCENTRY_INVOICE_ENTRY:
    case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
        /* Watch the invoice owner to see when items get added via orders */
        gnc_gui_component_watch_entity (ledger->component_id,
                                        gncOwnerGetGUID
                                        (gncInvoiceGetOwner (ledger->invoice)),
                                        QOF_EVENT_MODIFY);
    case GNCENTRY_INVOICE_VIEWER:
    case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
    case GNCENTRY_BILL_ENTRY:
    case GNCENTRY_BILL_VIEWER:
    case GNCENTRY_EXPVOUCHER_ENTRY:
    case GNCENTRY_EXPVOUCHER_VIEWER:
    case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
    case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
    case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
    case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
        type = GNC_INVOICE_MODULE_NAME;
        break;

    default:
        g_warning ("Invalid ledger type");
        break;
    }

    gnc_gui_component_watch_entity_type (ledger->component_id,
                                         type,
                                         QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);

    /* To make sure the xfer cell is up to date */
    gnc_gui_component_watch_entity_type (ledger->component_id,
                                         GNC_ID_ACCOUNT,
                                         QOF_EVENT_MODIFY | QOF_EVENT_DESTROY
                                         | GNC_EVENT_ITEM_CHANGED);

    /* To make sure the taxtable cell is up to date */
    gnc_gui_component_watch_entity_type (ledger->component_id,
                                         GNC_TAXTABLE_MODULE_NAME,
                                         QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);

    /* For expense vouchers, watch the employee and refresh if it's changed */
    if (ledger->type == GNCENTRY_EXPVOUCHER_ENTRY)
    {
        const GncOwner *owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
        GncEmployee *employee = gncOwnerGetEmployee (owner);

        if (employee)
            gnc_gui_component_watch_entity (ledger->component_id,
                                            gncEmployeeGetGUID (employee),
                                            QOF_EVENT_MODIFY);
    }

    for (node = entries; node; node = node->next)
    {
        GncEntry *entry = node->data;
        gnc_gui_component_watch_entity (ledger->component_id,
                                        gncEntryGetGUID (entry),
                                        QOF_EVENT_MODIFY);
    }
}
示例#10
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);
}