GnuCash 2.3.0
Files | Defines | Typedefs | Enumerations | Functions
Invoice
Business

Files

file  gncInvoice.h
 

Business Invoice Interface.


Defines

#define GNC_ID_INVOICE   "gncInvoice"
#define GNC_TYPE_INVOICE   (gnc_invoice_get_type ())
#define GNC_INVOICE(o)   (G_TYPE_CHECK_INSTANCE_CAST ((o), GNC_TYPE_INVOICE, GncInvoice))
#define GNC_INVOICE_CLASS(k)   (G_TYPE_CHECK_CLASS_CAST((k), GNC_TYPE_INVOICE, GncInvoiceClass))
#define GNC_IS_INVOICE(o)   (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNC_TYPE_INVOICE))
#define GNC_IS_INVOICE_CLASS(k)   (G_TYPE_CHECK_CLASS_TYPE ((k), GNC_TYPE_INVOICE))
#define GNC_INVOICE_GET_CLASS(o)   (G_TYPE_INSTANCE_GET_CLASS ((o), GNC_TYPE_INVOICE, GncInvoiceClass))
#define INVOICE_ID   "id"
#define INVOICE_OWNER   "owner"
#define INVOICE_OPENED   "date_opened"
#define INVOICE_POSTED   "date_posted"
#define INVOICE_DUE   "date_due"
#define INVOICE_IS_POSTED   "is_posted?"
#define INVOICE_IS_PAID   "is_paid?"
#define INVOICE_TERMS   "terms"
#define INVOICE_BILLINGID   "billing_id"
#define INVOICE_NOTES   "notes"
#define INVOICE_ACC   "account"
#define INVOICE_POST_TXN   "posted_txn"
#define INVOICE_POST_LOT   "posted_lot"
#define INVOICE_IS_CN   "credit_note"
#define INVOICE_TYPE   "type"
#define INVOICE_TYPE_STRING   "type_string"
#define INVOICE_BILLTO   "bill-to"
#define INVOICE_ENTRIES   "list_of_entries"
#define INVOICE_JOB   "invoice_job"
#define INVOICE_FROM_LOT   "invoice-from-lot"
#define INVOICE_FROM_TXN   "invoice-from-txn"
#define gncInvoiceGetGUID(x)   qof_instance_get_guid(QOF_INSTANCE(x))
#define gncInvoiceRetGUID(x)   (x ? *(qof_instance_get_guid(QOF_INSTANCE(x))) : *(guid_null()))
#define gncInvoiceLookupDirect(G, B)   gncInvoiceLookup((B),&(G))

Typedefs

typedef struct _gncInvoice GncInvoice
typedef struct _gncInvoiceClass GncInvoiceClass
typedef GList GncInvoiceList
typedef GList EntryList

Enumerations

enum  GncInvoiceType {
  GNC_INVOICE_UNDEFINED, GNC_INVOICE_CUST_INVOICE, GNC_INVOICE_VEND_INVOICE, GNC_INVOICE_EMPL_INVOICE,
  GNC_INVOICE_CUST_CREDIT_NOTE, GNC_INVOICE_VEND_CREDIT_NOTE, GNC_INVOICE_EMPL_CREDIT_NOTE, GNC_INVOICE_NUM_TYPES
}

Functions

GType gnc_invoice_get_type (void)
void gncInvoiceAddEntry (GncInvoice *invoice, GncEntry *entry)
void gncInvoiceRemoveEntry (GncInvoice *invoice, GncEntry *entry)
void gncInvoiceAddPrice (GncInvoice *invoice, GNCPrice *price)
void gncBillAddEntry (GncInvoice *bill, GncEntry *entry)
void gncBillRemoveEntry (GncInvoice *bill, GncEntry *entry)
void gncInvoiceSortEntries (GncInvoice *invoice)
gnc_numeric gncInvoiceGetTotal (GncInvoice *invoice)
gnc_numeric gncInvoiceGetTotalOf (GncInvoice *invoice, GncEntryPaymentType type)
gnc_numeric gncInvoiceGetTotalSubtotal (GncInvoice *invoice)
gnc_numeric gncInvoiceGetTotalTax (GncInvoice *invoice)
EntryList * gncInvoiceGetEntries (GncInvoice *invoice)
GNCPricegncInvoiceGetPrice (GncInvoice *invoice, gnc_commodity *commodity)
gboolean gncInvoiceAmountPositive (const GncInvoice *invoice)
TransactiongncInvoicePostToAccount (GncInvoice *invoice, Account *acc, Timespec *posted_date, Timespec *due_date, const char *memo, gboolean accumulatesplits)
gboolean gncInvoiceUnpost (GncInvoice *invoice, gboolean reset_tax_tables)
GncInvoicegncInvoiceGetInvoiceFromTxn (const Transaction *txn)
GncInvoicegncInvoiceGetInvoiceFromLot (GNCLot *lot)
void gncInvoiceBeginEdit (GncInvoice *invoice)
void gncInvoiceCommitEdit (GncInvoice *invoice)
int gncInvoiceCompare (const GncInvoice *a, const GncInvoice *b)
gboolean gncInvoiceIsPosted (const GncInvoice *invoice)
gboolean gncInvoiceIsPaid (const GncInvoice *invoice)
QofBookgncInvoiceGetBook (GncInvoice *x)
gboolean gncInvoiceEqual (const GncInvoice *a, const GncInvoice *b)

Create/Destroy Functions

GncInvoicegncInvoiceCreate (QofBook *book)
void gncInvoiceDestroy (GncInvoice *invoice)
GncInvoicegncInvoiceCopy (const GncInvoice *other_invoice)

Set Functions

void gncInvoiceSetID (GncInvoice *invoice, const char *id)
void gncInvoiceSetOwner (GncInvoice *invoice, GncOwner *owner)
void gncInvoiceSetDateOpenedGDate (GncInvoice *invoice, const GDate *date)
void gncInvoiceSetDateOpened (GncInvoice *invoice, Timespec date)
void gncInvoiceSetDatePosted (GncInvoice *invoice, Timespec date)
void gncInvoiceSetTerms (GncInvoice *invoice, GncBillTerm *terms)
void gncInvoiceSetBillingID (GncInvoice *invoice, const char *billing_id)
void gncInvoiceSetNotes (GncInvoice *invoice, const char *notes)
void gncInvoiceSetCurrency (GncInvoice *invoice, gnc_commodity *currency)
void gncInvoiceSetActive (GncInvoice *invoice, gboolean active)
void gncInvoiceSetIsCreditNote (GncInvoice *invoice, gboolean credit_note)
void gncInvoiceSetBillTo (GncInvoice *invoice, GncOwner *billto)
void gncInvoiceSetToChargeAmount (GncInvoice *invoice, gnc_numeric amount)

Get Functions

const char * gncInvoiceGetID (const GncInvoice *invoice)
const GncOwnergncInvoiceGetOwner (const GncInvoice *invoice)
Timespec gncInvoiceGetDateOpened (const GncInvoice *invoice)
Timespec gncInvoiceGetDatePosted (const GncInvoice *invoice)
Timespec gncInvoiceGetDateDue (const GncInvoice *invoice)
GncBillTermgncInvoiceGetTerms (const GncInvoice *invoice)
const char * gncInvoiceGetBillingID (const GncInvoice *invoice)
const char * gncInvoiceGetNotes (const GncInvoice *invoice)
GncOwnerType gncInvoiceGetOwnerType (const GncInvoice *invoice)
GList * gncInvoiceGetTypeListForOwnerType (const GncOwnerType type)
GncInvoiceType gncInvoiceGetType (const GncInvoice *invoice)
const char * gncInvoiceGetTypeString (const GncInvoice *invoice)
gnc_commoditygncInvoiceGetCurrency (const GncInvoice *invoice)
GncOwnergncInvoiceGetBillTo (GncInvoice *invoice)
gnc_numeric gncInvoiceGetToChargeAmount (const GncInvoice *invoice)
gboolean gncInvoiceGetActive (const GncInvoice *invoice)
gboolean gncInvoiceGetIsCreditNote (const GncInvoice *invoice)
GNCLotgncInvoiceGetPostedLot (const GncInvoice *invoice)
TransactiongncInvoiceGetPostedTxn (const GncInvoice *invoice)
AccountgncInvoiceGetPostedAcc (const GncInvoice *invoice)

Detailed Description

An invoice holds a list of entries, a pointer to the customer, and the job, the dates entered and posted, as well as the account, transaction and lot for the posted invoice.


Define Documentation

#define gncInvoiceGetGUID (   x)    qof_instance_get_guid(QOF_INSTANCE(x))

deprecated functions

Definition at line 248 of file gncInvoice.h.


Function Documentation

void gncBillAddEntry ( GncInvoice bill,
GncEntry entry 
)

Call this function when adding an entry to a bill instead of an invoice

Definition at line 639 of file gncInvoice.c.

{
    GncInvoice *old;

    g_assert(bill);
    g_assert(entry);
    if (!bill || !entry) return;

    old = gncEntryGetBill (entry);
    if (old == bill) return;    /* I already own this one */
    if (old) gncBillRemoveEntry (old, entry);

    gncEntrySetBill (entry, bill);
    bill->entries = g_list_insert_sorted (bill->entries, entry,
                                          (GCompareFunc)gncEntryCompare);
    mark_invoice (bill);
}
gboolean gncInvoiceAmountPositive ( const GncInvoice invoice)

Depending on the invoice type, invoices have a different effect on the balance. Customer invoices increase the balance, while vendor bills decrease the balance. Credit notes have the opposite effect.

Returns TRUE if the invoice will increase the balance or FALSE otherwise.

Definition at line 1153 of file gncInvoice.c.

{
    switch (gncInvoiceGetType (invoice))
    {
    case GNC_INVOICE_CUST_INVOICE:
    case GNC_INVOICE_VEND_CREDIT_NOTE:
    case GNC_INVOICE_EMPL_CREDIT_NOTE:
        return TRUE;
    case GNC_INVOICE_CUST_CREDIT_NOTE:
    case GNC_INVOICE_VEND_INVOICE:
    case GNC_INVOICE_EMPL_INVOICE:
        return FALSE;
    case GNC_INVOICE_UNDEFINED:
    default:
        /* Should never be reached.
         * If it is, perhaps a new value is added to GncInvoiceType ? */
        g_assert_not_reached();
        return FALSE;
    }
}
GncInvoice* gncInvoiceCopy ( const GncInvoice other_invoice)

Create a new GncInvoice object as a deep copy of the given other invoice.

The returned new invoice has everything copied from the other invoice, including the ID string field. All GncEntries are newly allocated copies of the original invoice's entries.

Definition at line 318 of file gncInvoice.c.

{
    GncInvoice *invoice;
    QofBook* book;
    GList *node;
    gint64 is_cn;

    g_assert(from);
    book = qof_instance_get_book(from);
    g_assert(book);

    invoice = g_object_new (GNC_TYPE_INVOICE, NULL);
    qof_instance_init_data (&invoice->inst, _GNC_MOD_NAME, book);

    gncInvoiceBeginEdit(invoice);

    invoice->id = CACHE_INSERT (from->id);
    invoice->notes = CACHE_INSERT (from->notes);
    invoice->billing_id = CACHE_INSERT (from->billing_id);
    invoice->active = from->active;

    is_cn = kvp_frame_get_gint64(from->inst.kvp_data, GNC_INVOICE_IS_CN);
    kvp_frame_set_gint64(invoice->inst.kvp_data, GNC_INVOICE_IS_CN, is_cn);

    invoice->terms = from->terms;
    gncBillTermIncRef (invoice->terms);

    gncOwnerCopy(&from->billto, &invoice->billto);
    gncOwnerCopy(&from->owner, &invoice->owner);
    invoice->job = from->job; // FIXME: Need IncRef or similar here?!?

    invoice->to_charge_amount = from->to_charge_amount;
    invoice->date_opened = from->date_opened;

    // Oops. Do not forget to copy the pointer to the correct currency here.
    invoice->currency = from->currency;

    // Copy all invoice->entries
    for (node = from->entries; node; node = node->next)
    {
        GncEntry *from_entry = node->data;
        GncEntry *to_entry = gncEntryCreate(book);
        gncEntryCopy(from_entry, to_entry);

        switch (gncInvoiceGetOwnerType (invoice))
        {
        case GNC_OWNER_VENDOR:
        case GNC_OWNER_EMPLOYEE:
            // this is a vendor bill, or an expense voucher
            gncBillAddEntry(invoice, to_entry);
            break;
        case GNC_OWNER_CUSTOMER:
        default:
            // this is an invoice
            gncInvoiceAddEntry(invoice, to_entry);
            break;
        }
    }

    // FIXME: The prices are not (yet) copied; is this a problem?

    // Posted-date and the posted Txn is intentionally not copied; the
    // copy isn't "posted" but needs to be posted by the user.

    gncInvoiceCommitEdit(invoice);

    return invoice;
}
gboolean gncInvoiceEqual ( const GncInvoice a,
const GncInvoice b 
)

Test support function used by test-dbi-business-stuff.c

Definition at line 1742 of file gncInvoice.c.

{
    if (a == NULL && b == NULL) return TRUE;
    if (a == NULL || b == NULL) return FALSE;

    g_return_val_if_fail(GNC_IS_INVOICE(a), FALSE);
    g_return_val_if_fail(GNC_IS_INVOICE(b), FALSE);

    if (safe_strcmp(a->id, b->id) != 0)
    {
        PWARN("IDs differ: %s vs %s", a->id, b->id);
        return FALSE;
    }

    if (safe_strcmp(a->notes, b->notes) != 0)
    {
        PWARN("Notes differ: %s vs %s", a->notes, b->notes);
        return FALSE;
    }

    if (safe_strcmp(a->billing_id, b->billing_id) != 0)
    {
        PWARN("Billing IDs differ: %s vs %s", a->billing_id, b->billing_id);
        return FALSE;
    }

    if (safe_strcmp(a->printname, b->printname) != 0)
    {
        PWARN("Printnames differ: %s vs %s", a->printname, b->printname);
        return FALSE;
    }

    if (a->active != b->active)
    {
        PWARN("Active flags differ");
        return FALSE;
    }

    if (!gncBillTermEqual(a->terms, b->terms))
    {
        PWARN("Billterms differ");
        return FALSE;
    }

    if (!gncJobEqual(a->job, b->job))
    {
        PWARN("Jobs differ");
        return FALSE;
    }

    if (!gnc_commodity_equal(a->currency, b->currency))
    {
        PWARN("Currencies differ");
        return FALSE;
    }

    if (!xaccAccountEqual(a->posted_acc, b->posted_acc, TRUE))
    {
        PWARN("Posted accounts differ");
        return FALSE;
    }

    if (!xaccTransEqual(a->posted_txn, b->posted_txn, TRUE, TRUE, TRUE, FALSE))
    {
        PWARN("Posted tx differ");
        return FALSE;
    }

#if 0
    if (!gncLotEqual(a->posted_lot, b->posted_lot))
    {
        PWARN("Posted lots differ");
        return FALSE;
    }
#endif

    /* FIXME: Need real checks */
#if 0
    GList       *entries;
    GList       *prices;
    GncOwner    owner;
    GncOwner    billto;
    Timespec    date_opened;
    Timespec    date_posted;

    gnc_numeric to_charge_amount;
#endif

    return TRUE;
}
GncInvoice* gncInvoiceGetInvoiceFromLot ( GNCLot lot)

Given a LOT, find and return the Invoice attached to the lot

Definition at line 1095 of file gncInvoice.c.

{
    KvpFrame *kvp;
    KvpValue *value;
    GncGUID *guid;
    QofBook *book;

    if (!lot) return NULL;

    book = gnc_lot_get_book (lot);
    kvp = gnc_lot_get_slots (lot);
    value = kvp_frame_get_slot_path (kvp, GNC_INVOICE_ID, GNC_INVOICE_GUID, NULL);
    if (!value) return NULL;

    guid = kvp_value_get_guid (value);
    return gncInvoiceLookup(book, guid);
}
GncInvoice* gncInvoiceGetInvoiceFromTxn ( const Transaction txn)

Given a transaction, find and return the Invoice

Definition at line 1135 of file gncInvoice.c.

{
    KvpFrame *kvp;
    KvpValue *value;
    GncGUID *guid;
    QofBook *book;

    if (!txn) return NULL;

    book = xaccTransGetBook (txn);
    kvp = xaccTransGetSlots (txn);
    value = kvp_frame_get_slot_path (kvp, GNC_INVOICE_ID, GNC_INVOICE_GUID, NULL);
    if (!value) return NULL;

    guid = kvp_value_get_guid (value);
    return gncInvoiceLookup(book, guid);
}
gnc_numeric gncInvoiceGetTotal ( GncInvoice invoice)

return the "total" amount of the invoice

Definition at line 817 of file gncInvoice.c.

{
    if (!invoice) return gnc_numeric_zero();
    return gncInvoiceGetTotalInternal(invoice, TRUE, TRUE, FALSE, 0);
}
Transaction* gncInvoicePostToAccount ( GncInvoice invoice,
Account acc,
Timespec posted_date,
Timespec due_date,
const char *  memo,
gboolean  accumulatesplits 
)

Post this invoice to an account. Returns the new Transaction that is tied to this invoice. The transaction is set with the supplied posted date, due date, and memo. The Transaction description is set to the name of the company.

Definition at line 1205 of file gncInvoice.c.

{
    Transaction *txn;
    QofBook *book;
    GNCLot *lot = NULL;
    GList *iter;
    GList *splitinfo = NULL;
    gnc_numeric total;
    gboolean positive_balance;
    gboolean is_cust_doc;
    const char *name, *type;
    char *lot_title;
    Account *ccard_acct = NULL;
    const GncOwner *owner;

    if (!invoice || !acc) return NULL;

    gncInvoiceBeginEdit (invoice);
    book = qof_instance_get_book(invoice);

    /* Stabilize the Billing Terms of this invoice */
    if (invoice->terms)
        gncInvoiceSetTerms (invoice,
                            gncBillTermReturnChild (invoice->terms, TRUE));

    /* Does the invoice/credit note have a positive effect on the balance ? Note that
     * payments for such invoices by definition then have a negative effect on the balance.
     * This is used to determine which open lots can be considered when posting the invoice. */
    positive_balance = gncInvoiceAmountPositive (invoice);

    /* GncEntry functions need to know if the invoice/credit note is for a customer or a vendor/employee. */
    is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);

    /* Figure out if we need to separate out "credit-card" items */
    owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
    if (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_EMPLOYEE)
        ccard_acct = gncEmployeeGetCCard (gncOwnerGetEmployee (owner));

    /* Find an existing payment-lot for this owner */
    {
        LotList *lot_list;
        struct lotmatch lm;

        lm.positive_balance = positive_balance;
        lm.owner = owner;

        lot_list = xaccAccountFindOpenLots (acc, gnc_lot_match_owner_payment,
                                            &lm, NULL);
        if (lot_list)
            lot = lot_list->data;

        g_list_free (lot_list);
    }

    /* Create a new lot for this invoice, if we need to do so */
    if (!lot)
        lot = gnc_lot_new (book);
    gnc_lot_begin_edit (lot);

    type = gncInvoiceGetTypeString (invoice);

    /* Set the lot title */
    lot_title = g_strdup_printf ("%s %s", type, gncInvoiceGetID (invoice));
    gnc_lot_set_title (lot, lot_title);
    g_free (lot_title);

    /* Create a new transaction */
    txn = xaccMallocTransaction (book);
    xaccTransBeginEdit (txn);

    name = gncOwnerGetName (gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice)));

    /* Set Transaction Description (Owner Name) , Num (invoice ID), Currency */
    xaccTransSetDescription (txn, name ? name : "");
    xaccTransSetNum (txn, gncInvoiceGetID (invoice));
    xaccTransSetCurrency (txn, invoice->currency);

    /* Entered and Posted at date */
    xaccTransSetDateEnteredSecs (txn, time(NULL));
    if (post_date)
    {
        xaccTransSetDatePostedTS (txn, post_date);
        gncInvoiceSetDatePosted (invoice, *post_date);
    }

    if (due_date)
        xaccTransSetDateDueTS (txn, due_date);

    /* Iterate through the entries; sum up everything for each account.
     * then create the appropriate splits in this txn.
     */
    total = gnc_numeric_zero();
    for (iter = gncInvoiceGetEntries(invoice); iter; iter = iter->next)
    {
        gnc_numeric value, tax;
        GList *taxes;
        GncEntry * entry = iter->data;
        Account *this_acc;

        /* Stabilize the TaxTable in this entry */
        gncEntryBeginEdit (entry);
        if (is_cust_doc)
            gncEntrySetInvTaxTable
            (entry, gncTaxTableReturnChild (gncEntryGetInvTaxTable (entry), TRUE));
        else
        {
            gncEntrySetBillTaxTable
            (entry, gncTaxTableReturnChild (gncEntryGetBillTaxTable (entry), TRUE));

            /* If this is a bill, and the entry is billable, copy the price */
            if (gncEntryGetBillable (entry))
                gncEntrySetInvPrice (entry, gncEntryGetBillPrice (entry));
        }
        gncEntryCommitEdit (entry);

        /* Obtain the Entry's Value and TaxValues */
        gncEntryGetValue (entry, is_cust_doc, &value, NULL, &tax, &taxes);

        /* add the value for the account split */
        this_acc = (is_cust_doc ? gncEntryGetInvAccount (entry) :
                    gncEntryGetBillAccount (entry));
        if (this_acc)
        {
            if (gnc_numeric_check (value) == GNC_ERROR_OK)
            {
                if (accumulatesplits)
                {
                    splitinfo = gncAccountValueAdd (splitinfo, this_acc, value);
                }
                else
                {
                    Split *split;

                    split = xaccMallocSplit (book);
                    /* set action and memo? */

                    xaccSplitSetMemo (split, gncEntryGetDescription (entry));
                    xaccSplitSetAction (split, type);

                    /* Need to insert this split into the account AND txn before
                     * we set the Base Value.  Otherwise SetBaseValue complains
                     * that we don't have an account and fails to set the value.
                     */
                    xaccAccountBeginEdit (this_acc);
                    xaccAccountInsertSplit (this_acc, split);
                    xaccAccountCommitEdit (this_acc);
                    xaccTransAppendSplit (txn, split);

                    /* General note on the split creations below:
                     * Invoice and bill amounts are always stored as positive values in entries
                     * So to convert them to proper splits, the amounts may have to be reverted
                     * to have the proper effect on the account balance.
                     * Credit notes have the opposite effect of invoices/bills, but their amounts
                     * are stored as negative values as well. So to convert them into splits
                     * they can be treated exactly the same as their invoice/bill counter parts.
                     * The net effect is that the owner type is sufficient to determine whether a
                     * value has to be reverted when converting an invoice/bill/cn amount to a split.
                     */
                    if (gnc_commodity_equal(xaccAccountGetCommodity(this_acc), invoice->currency))
                    {
                        xaccSplitSetBaseValue (split, (is_cust_doc ? gnc_numeric_neg (value)
                                                       : value),
                                               invoice->currency);
                    }
                    else
                    {
                        /*need to do conversion */
                        GNCPrice *price = gncInvoiceGetPrice(invoice, xaccAccountGetCommodity(this_acc));

                        if (price == NULL)
                        {
                            /*This is an error, which shouldn't even be able to happen.
                              We can't really do anything sensible about it, and this is
                                            a user-interface free zone so we can't try asking the user
                              again either, have to return NULL*/
                            return NULL;
                        }
                        else
                        {
                            gnc_numeric converted_amount;
                            xaccSplitSetValue(split, (is_cust_doc ? gnc_numeric_neg(value) : value));
                            converted_amount = gnc_numeric_div(value, gnc_price_get_value(price), GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
                            DEBUG("converting from %f to %f\n", gnc_numeric_to_double(value), gnc_numeric_to_double(converted_amount));
                            xaccSplitSetAmount(split, is_cust_doc ? gnc_numeric_neg(converted_amount) : converted_amount);
                        }
                    }
                }

                /* If there is a credit-card account, and this is a CCard
                 * payment type, the don't add it to the total, and instead
                 * create a split to the CC Acct with a memo of the entry
                 * description instead of the provided memo.  Note that the
                 * value reversal is the same as the post account.
                 *
                 * Note: we don't have to worry about the tax values --
                 * expense vouchers don't have them.
                 */
                if (ccard_acct && gncEntryGetBillPayment (entry) == GNC_PAYMENT_CARD)
                {
                    Split *split;

                    split = xaccMallocSplit (book);
                    /* set action? */
                    xaccSplitSetMemo (split, gncEntryGetDescription (entry));
                    xaccSplitSetAction (split, type);
                    xaccAccountBeginEdit (ccard_acct);
                    xaccAccountInsertSplit (ccard_acct, split);
                    xaccAccountCommitEdit (ccard_acct);
                    xaccTransAppendSplit (txn, split);
                    xaccSplitSetBaseValue (split, (is_cust_doc ? value : gnc_numeric_neg (value)),
                                           invoice->currency);

                }
                else
                    total = gnc_numeric_add (total, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);

            }
            else
                g_warning ("bad value in our entry");
        }

        /* now merge in the TaxValues */
        splitinfo = gncAccountValueAddList (splitinfo, taxes);

        /* ... and add the tax total */
        if (gnc_numeric_check (tax) == GNC_ERROR_OK)
            total = gnc_numeric_add (total, tax, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
        else
            g_warning ("bad tax in our entry");

    } /* for */

    /* Iterate through the splitinfo list and generate the splits */
    for (iter = splitinfo; iter; iter = iter->next)
    {
        Split *split;
        GncAccountValue *acc_val = iter->data;

        split = xaccMallocSplit (book);
        /* set action and memo? */

        xaccSplitSetMemo (split, memo);
        xaccSplitSetAction (split, type);

        xaccAccountBeginEdit (acc_val->account);
        xaccAccountInsertSplit (acc_val->account, split);
        xaccAccountCommitEdit (acc_val->account);
        xaccTransAppendSplit (txn, split);

        if (gnc_commodity_equal(xaccAccountGetCommodity(acc_val->account), invoice->currency))
        {
            xaccSplitSetBaseValue (split, (is_cust_doc ? gnc_numeric_neg (acc_val->value)
                                           : acc_val->value),
                                   invoice->currency);
        }
        else
        {
            /*need to do conversion */
            GNCPrice *price = gncInvoiceGetPrice(invoice, xaccAccountGetCommodity(acc_val->account));

            if (price == NULL)
            {
                /*This is an error, which shouldn't even be able to happen.
                  We can't really do anything sensible about it, and this is
                  a user-interface free zone so we can't try asking the user
                  again either, have to return NULL*/
                return NULL;
            }
            else
            {
                gnc_numeric converted_amount;
                xaccSplitSetValue(split, (is_cust_doc ? gnc_numeric_neg(acc_val->value) : acc_val->value));
                converted_amount = gnc_numeric_div(acc_val->value, gnc_price_get_value(price), GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
                DEBUG("converting from %f to %f\n", gnc_numeric_to_double(acc_val->value), gnc_numeric_to_double(converted_amount));

                xaccSplitSetAmount(split, is_cust_doc ? gnc_numeric_neg(converted_amount) : converted_amount);
            }
        }
    }

    /* If there is a ccard account, we may have an additional "to_card" payment.
     * we should make that now..
     */
    if (ccard_acct && !gnc_numeric_zero_p (invoice->to_charge_amount))
    {
        Split *split = xaccMallocSplit (book);

        /* Set memo.  action? */
        xaccSplitSetMemo (split, _("Extra to Charge Card"));
        xaccSplitSetAction (split, type);

        xaccAccountBeginEdit (ccard_acct);
        xaccAccountInsertSplit (ccard_acct, split);
        xaccAccountCommitEdit (ccard_acct);
        xaccTransAppendSplit (txn, split);
        xaccSplitSetBaseValue (split, (is_cust_doc ? invoice->to_charge_amount :
                                       gnc_numeric_neg(invoice->to_charge_amount)),
                               invoice->currency);

        total = gnc_numeric_sub (total, invoice->to_charge_amount,
                                 GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
    }

    /* Now create the Posted split (which is the opposite sign of the above splits) */
    {
        Split *split = xaccMallocSplit (book);

        /* Set action/memo */
        xaccSplitSetMemo (split, memo);
        xaccSplitSetAction (split, type);

        xaccAccountBeginEdit (acc);
        xaccAccountInsertSplit (acc, split);
        xaccAccountCommitEdit (acc);
        xaccTransAppendSplit (txn, split);
        xaccSplitSetBaseValue (split, (is_cust_doc ? total : gnc_numeric_neg (total)),
                               invoice->currency);

        /* add this split to the lot */
        gnc_lot_add_split (lot, split);
    }

    /* Now attach this invoice to the txn, lot, and account */
    gncInvoiceAttachToLot (invoice, lot);
    gncInvoiceAttachToTxn (invoice, txn);
    gncInvoiceSetPostedAcc (invoice, acc);

    xaccTransSetReadOnly (txn, _("Generated from an invoice.  Try unposting the invoice."));
    xaccTransCommitEdit (txn);

    gncAccountValueDestroy (splitinfo);

    /* check the lot -- if we still look like a payment lot, then that
     * means we need to create a balancing split and create a new payment
     * lot for the next invoice
     *
     * we're looking for a positive balance for bill/AP, and a negative balance
     * for invoice/AR.
     * (because bill payments debit AP accounts and invoice payments
     * credit AR accounts)
     */
    total = gnc_lot_get_balance (lot);

    if ( (gnc_numeric_negative_p (total) && positive_balance) ||
            (gnc_numeric_positive_p (total) && !positive_balance) )
    {
        Transaction *t2;
        GNCLot *lot2;
        Split *split;
        /* Translators: This is the memo of an auto-created split */
        char *memo2 = _("Automatic Payment Forward");
        char *action2 = _("Auto Split");

        t2 = xaccMallocTransaction (book);
        lot2 = gnc_lot_new (book);
        gnc_lot_begin_edit (lot2);
        gncOwnerAttachToLot (gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice)),
                             lot2);

        xaccTransBeginEdit (t2);
        xaccAccountBeginEdit (acc);

        /* Set Transaction Description (Owner Name), Currency */
        xaccTransSetDescription (t2, name ? name : "");
        xaccTransSetCurrency (t2, invoice->currency);

        /* Entered and Posted at date */
        xaccTransSetDateEnteredSecs (t2, time(NULL));
        if (post_date)
            xaccTransSetDatePostedTS (t2, post_date);

        /* Balance out this lot */
        split = xaccMallocSplit (book);
        xaccSplitSetMemo (split, memo2);
        xaccSplitSetAction (split, action2);
        xaccAccountInsertSplit (acc, split);
        xaccTransAppendSplit (t2, split);
        // the value of total used here is correct for both bill/AP and
        // invoice/AR. See the comment before this if block
        xaccSplitSetBaseValue (split, gnc_numeric_neg (total),
                               invoice->currency);
        gnc_lot_add_split (lot, split);

        /* And apply the pre-payment to a new lot */
        split = xaccMallocSplit (book);
        xaccSplitSetMemo (split, memo2);
        xaccSplitSetAction (split, action2);
        xaccAccountInsertSplit (acc, split);
        xaccTransAppendSplit (t2, split);
        xaccSplitSetBaseValue (split, total, invoice->currency);
        gnc_lot_add_split (lot2, split);

        gnc_lot_commit_edit (lot2);
        xaccTransCommitEdit (t2);
        xaccAccountCommitEdit (acc);
    }

    gnc_lot_commit_edit (lot);
    gncInvoiceCommitEdit (invoice);

    return txn;
}
void gncInvoiceSetDateOpenedGDate ( GncInvoice invoice,
const GDate *  date 
)

Set the DateOpened using a GDate argument. (Note: Internally this stores the date in a Timespec as created through timespecCanonicalDayTime()).

Definition at line 462 of file gncInvoice.c.

{
    g_assert (date);
    gncInvoiceSetDateOpened(invoice, timespecCanonicalDayTime(gdate_to_timespec(*date)));
}
void gncInvoiceSortEntries ( GncInvoice invoice)

Call this function when an Entry is changed and you want to re-sort the list of entries

Definition at line 666 of file gncInvoice.c.

{
    if (!invoice) return;
    invoice->entries = g_list_sort(invoice->entries,
                                   (GCompareFunc)gncEntryCompare);
    mark_invoice(invoice);
}
gboolean gncInvoiceUnpost ( GncInvoice invoice,
gboolean  reset_tax_tables 
)

UNpost this invoice. This will destroy the posted transaction and return the invoice to its unposted state. It may leave empty lots out there. If reset_tax_tables is TRUE, then it will also revert all the Tax Tables to the parent, which will potentially change the total value of the invoice. It may also leave some orphaned Tax Table children.

Returns TRUE if successful, FALSE if there is a problem.

Definition at line 1611 of file gncInvoice.c.

{
    Transaction *txn;
    GNCLot *lot;

    if (!invoice) return FALSE;
    if (!gncInvoiceIsPosted (invoice)) return FALSE;

    txn = gncInvoiceGetPostedTxn (invoice);
    g_return_val_if_fail (txn, FALSE);

    lot = gncInvoiceGetPostedLot (invoice);
    g_return_val_if_fail (lot, FALSE);

    /* Destroy the Posted Transaction */
    xaccTransClearReadOnly (txn);
    xaccTransBeginEdit (txn);
    xaccTransDestroy (txn);
    xaccTransCommitEdit (txn);

    /* Disconnect the lot from the invoice; re-attach to the invoice owner */
    gncInvoiceDetachFromLot (lot);
    gncOwnerAttachToLot (&invoice->owner, lot);

    /* If the lot has no splits, then destroy it */
    if (!gnc_lot_count_splits (lot))
        gnc_lot_destroy (lot);

    /* Clear out the invoice posted information */
    gncInvoiceBeginEdit (invoice);

    invoice->posted_acc = NULL;
    invoice->posted_txn = NULL;
    invoice->posted_lot = NULL;
    invoice->date_posted.tv_sec = invoice->date_posted.tv_nsec = 0;

    /* if we've been asked to reset the tax tables, then do so */
    if (reset_tax_tables)
    {
        gboolean is_cust_doc = (gncInvoiceGetOwnerType(invoice) == GNC_OWNER_CUSTOMER);
        GList *iter;

        for (iter = gncInvoiceGetEntries(invoice); iter; iter = iter->next)
        {
            GncEntry *entry = iter->data;

            gncEntryBeginEdit(entry);
            if (is_cust_doc)
                gncEntrySetInvTaxTable(entry,
                                       gncTaxTableGetParent(gncEntryGetInvTaxTable(entry)));
            else
                gncEntrySetBillTaxTable(entry,
                                        gncTaxTableGetParent(gncEntryGetBillTaxTable(entry)));
            gncEntryCommitEdit(entry);
        }
    }

    mark_invoice (invoice);
    gncInvoiceCommitEdit (invoice);

    return TRUE;
}
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines