Integrate the tax table into the gncEntry object; change how taxes

and discounts are computed, stored, and returned.  Fix the Entry
	XML code to save/load the new taxtable data (not backwards
	compatible).  Integrate new changes into the entry-ledger.

	fix some bugs in the business xml code.  fix some memory leaks.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@6966 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Derek Atkins 2002-06-16 05:11:33 +00:00
parent 3738df9fc4
commit 8ef6d641be
23 changed files with 1014 additions and 529 deletions

View File

@ -1,3 +1,12 @@
2002-06-16 Derek Atkins <derek@ihtfp.com>
Integrate the tax table into the gncEntry object; change how taxes
and discounts are computed, stored, and returned. Fix the Entry
XML code to save/load the new taxtable data (not backwards
compatible). Integrate new changes into the entry-ledger.
fix some bugs in the business xml code. fix some memory leaks.
2002-06-14 Derek Atkins <derek@ihtfp.com>
* business-core/file/gnc-tax-table-xml-v2.*: Create a preliminary

View File

@ -21,6 +21,7 @@
#include "gncJobP.h"
#include "gncOrderP.h"
#include "gncOwnerP.h"
#include "gncTaxTableP.h"
#include "gncVendorP.h"
/* version of the gnc module system interface we require */

View File

@ -309,26 +309,23 @@ static GncCustomer*
dom_tree_to_customer (xmlNodePtr node, GNCBook *book)
{
struct customer_pdata cust_pdata;
GncCustomer *custToRet;
gboolean successful;
custToRet = gncCustomerCreate(book);
cust_pdata.customer = custToRet;
cust_pdata.customer = gncCustomerCreate(book);
cust_pdata.book = book;
successful = dom_tree_generic_parse (node, customer_handlers_v2,
&cust_pdata);
gncCustomerCommitEdit (custToRet);
gncCustomerCommitEdit (cust_pdata.customer);
if (!successful)
{
PERR ("failed to parse customer tree");
gncCustomerDestroy (custToRet);
custToRet = NULL;
gncCustomerDestroy (cust_pdata.customer);
cust_pdata.customer = NULL;
}
return custToRet;
return cust_pdata.customer;
}
static gboolean

View File

@ -275,26 +275,23 @@ static GncEmployee*
dom_tree_to_employee (xmlNodePtr node, GNCBook *book)
{
struct employee_pdata employee_pdata;
GncEmployee *employeeToRet;
gboolean successful;
employeeToRet = gncEmployeeCreate(book);
employee_pdata.employee = employeeToRet;
employee_pdata.employee = gncEmployeeCreate(book);
employee_pdata.book = book;
successful = dom_tree_generic_parse (node, employee_handlers_v2,
&employee_pdata);
gncEmployeeCommitEdit (employeeToRet);
gncEmployeeCommitEdit (employee_pdata.employee);
if (!successful)
{
PERR ("failed to parse employee tree");
gncEmployeeDestroy (employeeToRet);
employeeToRet = NULL;
gncEmployeeDestroy (employee_pdata.employee);
employee_pdata.employee = NULL;
}
return employeeToRet;
return employee_pdata.employee;
}
static gboolean

View File

@ -44,6 +44,7 @@
#include "gncEntryP.h"
#include "gncOrderP.h"
#include "gncInvoiceP.h"
#include "gncTaxTableP.h"
#include "gnc-entry-xml-v2.h"
#include "gnc-owner-xml-v2.h"
#include "gnc-engine-util.h"
@ -65,12 +66,13 @@ const gchar *entry_version_string = "2.0.0";
#define entry_action_string "entry:action"
#define entry_qty_string "entry:qty"
#define entry_price_string "entry:price"
#define entry_tax_string "entry:tax"
#define entry_taxtype_string "entry:taxtype"
#define entry_discount_string "entry:discount"
#define entry_disctype_string "entry:disc-type"
#define entry_dischow_string "entry:disc-how"
#define entry_acct_string "entry:acct"
#define entry_taxacc_string "entry:taxacc"
#define entry_taxable_string "entry:taxable"
#define entry_taxincluded_string "entry:taxincluded"
#define entry_taxtable_string "entry:taxtable"
#define entry_order_string "entry:order"
#define entry_invoice_string "entry:invoice"
@ -94,6 +96,7 @@ entry_dom_tree_create (GncEntry *entry)
xmlNodePtr ret;
Timespec ts;
Account *acc;
GncTaxTable *taxtable;
GncOrder *order;
GncInvoice *invoice;
@ -115,24 +118,26 @@ entry_dom_tree_create (GncEntry *entry)
maybe_add_numeric (ret, entry_qty_string, gncEntryGetQuantity (entry));
maybe_add_numeric (ret, entry_price_string, gncEntryGetPrice (entry));
maybe_add_numeric (ret, entry_tax_string, gncEntryGetTax (entry));
xmlAddChild(ret, int_to_dom_tree(entry_taxtype_string,
gncEntryGetTaxType (entry)));
maybe_add_numeric (ret, entry_discount_string, gncEntryGetDiscount (entry));
xmlAddChild(ret, int_to_dom_tree(entry_disctype_string,
gncEntryGetDiscountType (entry)));
xmlAddChild(ret, int_to_dom_tree(entry_dischow_string,
gncEntryGetDiscountHow (entry)));
acc = gncEntryGetAccount (entry);
if (acc)
xmlAddChild (ret, guid_to_dom_tree (entry_acct_string,
xaccAccountGetGUID (acc)));
acc = gncEntryGetTaxAccount (entry);
if (acc)
xmlAddChild (ret, guid_to_dom_tree (entry_taxacc_string,
xaccAccountGetGUID (acc)));
xmlAddChild(ret, int_to_dom_tree(entry_taxable_string,
gncEntryGetTaxable (entry)));
xmlAddChild(ret, int_to_dom_tree(entry_taxincluded_string,
gncEntryGetTaxIncluded (entry)));
taxtable = gncEntryGetTaxTable (entry);
if (taxtable)
xmlAddChild (ret, guid_to_dom_tree (entry_taxtable_string,
gncTaxTableGetGUID (taxtable)));
order = gncEntryGetOrder (entry);
if (order)
@ -261,26 +266,6 @@ entry_price_handler (xmlNodePtr node, gpointer entry_pdata)
return set_numeric(node, pdata->entry, gncEntrySetPrice);
}
static gboolean
entry_tax_handler (xmlNodePtr node, gpointer entry_pdata)
{
struct entry_pdata *pdata = entry_pdata;
return set_numeric(node, pdata->entry, gncEntrySetTax);
}
static gboolean
entry_taxtype_handler (xmlNodePtr node, gpointer entry_pdata)
{
struct entry_pdata *pdata = entry_pdata;
gint64 val;
dom_tree_to_integer(node, &val);
gncEntrySetTaxType(pdata->entry, (int)val);
return TRUE;
}
static gboolean
entry_discount_handler (xmlNodePtr node, gpointer entry_pdata)
{
@ -301,6 +286,18 @@ entry_disctype_handler (xmlNodePtr node, gpointer entry_pdata)
return TRUE;
}
static gboolean
entry_dischow_handler (xmlNodePtr node, gpointer entry_pdata)
{
struct entry_pdata *pdata = entry_pdata;
gint64 val;
dom_tree_to_integer(node, &val);
gncEntrySetDiscountHow(pdata->entry, (gint)val);
return TRUE;
}
static gboolean
entry_acct_handler (xmlNodePtr node, gpointer entry_pdata)
{
@ -319,19 +316,47 @@ entry_acct_handler (xmlNodePtr node, gpointer entry_pdata)
}
static gboolean
entry_taxacc_handler (xmlNodePtr node, gpointer entry_pdata)
entry_taxable_handler (xmlNodePtr node, gpointer entry_pdata)
{
struct entry_pdata *pdata = entry_pdata;
gint64 val;
dom_tree_to_integer(node, &val);
gncEntrySetTaxable(pdata->entry, (gint)val);
return TRUE;
}
static gboolean
entry_taxincluded_handler (xmlNodePtr node, gpointer entry_pdata)
{
struct entry_pdata *pdata = entry_pdata;
gint64 val;
dom_tree_to_integer(node, &val);
gncEntrySetTaxIncluded(pdata->entry, (gint)val);
return TRUE;
}
static gboolean
entry_taxtable_handler (xmlNodePtr node, gpointer entry_pdata)
{
struct entry_pdata *pdata = entry_pdata;
GUID *guid;
Account * acc;
GncTaxTable *taxtable;
guid = dom_tree_to_guid (node);
g_return_val_if_fail (guid, FALSE);
acc = xaccAccountLookup (guid, pdata->book);
g_free (guid);
g_return_val_if_fail (acc, FALSE);
taxtable = gncTaxTableLookup (pdata->book, guid);
if (!taxtable) {
taxtable = gncTaxTableCreate (pdata->book);
gncTaxTableSetGUID (taxtable, guid);
} else
gncTaxTableDecRef (taxtable);
gncEntrySetTaxTable (pdata->entry, taxtable);
gncEntrySetTaxAccount (pdata->entry, acc);
g_free(guid);
return TRUE;
}
@ -383,12 +408,13 @@ static struct dom_tree_handler entry_handlers_v2[] = {
{ entry_action_string, entry_action_handler, 0, 0 },
{ entry_qty_string, entry_qty_handler, 0, 0 },
{ entry_price_string, entry_price_handler, 0, 0 },
{ entry_tax_string, entry_tax_handler, 0, 0 },
{ entry_taxtype_string, entry_taxtype_handler, 0, 0 },
{ entry_discount_string, entry_discount_handler, 0, 0 },
{ entry_disctype_string, entry_disctype_handler, 0, 0 },
{ entry_dischow_string, entry_dischow_handler, 0, 0 },
{ entry_acct_string, entry_acct_handler, 0, 0 },
{ entry_taxacc_string, entry_taxacc_handler, 0, 0 },
{ entry_taxable_string, entry_taxable_handler, 0, 0 },
{ entry_taxincluded_string, entry_taxincluded_handler, 0, 0 },
{ entry_taxtable_string, entry_taxtable_handler, 0, 0 },
{ entry_order_string, entry_order_handler, 0, 0 },
{ entry_invoice_string, entry_invoice_handler, 0, 0 },
{ NULL, 0, 0, 0 }
@ -398,26 +424,23 @@ static GncEntry*
dom_tree_to_entry (xmlNodePtr node, GNCBook *book)
{
struct entry_pdata entry_pdata;
GncEntry *entryToRet;
gboolean successful;
entryToRet = gncEntryCreate(book);
entry_pdata.entry = entryToRet;
entry_pdata.entry = gncEntryCreate(book);
entry_pdata.book = book;
successful = dom_tree_generic_parse (node, entry_handlers_v2,
&entry_pdata);
gncEntryCommitEdit (entryToRet);
gncEntryCommitEdit (entry_pdata.entry);
if (!successful)
{
PERR ("failed to parse entry tree");
gncEntryDestroy (entryToRet);
entryToRet = NULL;
gncEntryDestroy (entry_pdata.entry);
entry_pdata.entry = NULL;
}
return entryToRet;
return entry_pdata.entry;
}
static gboolean

View File

@ -335,26 +335,23 @@ static GncInvoice*
dom_tree_to_invoice (xmlNodePtr node, GNCBook *book)
{
struct invoice_pdata invoice_pdata;
GncInvoice *invoiceToRet;
gboolean successful;
invoiceToRet = gncInvoiceCreate(book);
invoice_pdata.invoice = invoiceToRet;
invoice_pdata.invoice = gncInvoiceCreate(book);
invoice_pdata.book = book;
successful = dom_tree_generic_parse (node, invoice_handlers_v2,
&invoice_pdata);
gncInvoiceCommitEdit (invoiceToRet);
gncInvoiceCommitEdit (invoice_pdata.invoice);
if (!successful)
{
PERR ("failed to parse invoice tree");
gncInvoiceDestroy (invoiceToRet);
invoiceToRet = NULL;
gncInvoiceDestroy (invoice_pdata.invoice);
invoice_pdata.invoice = NULL;
}
return invoiceToRet;
return invoice_pdata.invoice;
}
static gboolean

View File

@ -208,26 +208,23 @@ static GncJob*
dom_tree_to_job (xmlNodePtr node, GNCBook *book)
{
struct job_pdata job_pdata;
GncJob *jobToRet;
gboolean successful;
jobToRet = gncJobCreate(book);
job_pdata.job = jobToRet;
job_pdata.job = gncJobCreate(book);
job_pdata.book = book;
successful = dom_tree_generic_parse (node, job_handlers_v2,
&job_pdata);
gncJobCommitEdit (jobToRet);
gncJobCommitEdit (job_pdata.job);
if (!successful)
{
PERR ("failed to parse job tree");
gncJobDestroy (jobToRet);
jobToRet = NULL;
gncJobDestroy (job_pdata.job);
job_pdata.job = NULL;
}
return jobToRet;
return job_pdata.job;
}
static gboolean

View File

@ -246,26 +246,23 @@ static GncOrder*
dom_tree_to_order (xmlNodePtr node, GNCBook *book)
{
struct order_pdata order_pdata;
GncOrder *orderToRet;
gboolean successful;
orderToRet = gncOrderCreate(book);
order_pdata.order = orderToRet;
order_pdata.order = gncOrderCreate(book);
order_pdata.book = book;
successful = dom_tree_generic_parse (node, order_handlers_v2,
&order_pdata);
gncOrderCommitEdit (orderToRet);
gncOrderCommitEdit (order_pdata.order);
if (!successful)
{
PERR ("failed to parse order tree");
gncOrderDestroy (orderToRet);
orderToRet = NULL;
gncOrderDestroy (order_pdata.order);
order_pdata.order = NULL;
}
return orderToRet;
return order_pdata.order;
}
static gboolean

View File

@ -253,26 +253,23 @@ static GncVendor*
dom_tree_to_vendor (xmlNodePtr node, GNCBook *book)
{
struct vendor_pdata vendor_pdata;
GncVendor *vendorToRet;
gboolean successful;
vendorToRet = gncVendorCreate(book);
vendor_pdata.vendor = vendorToRet;
vendor_pdata.vendor = gncVendorCreate(book);
vendor_pdata.book = book;
successful = dom_tree_generic_parse (node, vendor_handlers_v2,
&vendor_pdata);
gncVendorCommitEdit (vendorToRet);
gncVendorCommitEdit (vendor_pdata.vendor);
if (!successful)
{
PERR ("failed to parse vendor tree");
gncVendorDestroy (vendorToRet);
vendorToRet = NULL;
gncVendorDestroy (vendor_pdata.vendor);
vendor_pdata.vendor = NULL;
}
return vendorToRet;
return vendor_pdata.vendor;
}
static gboolean

View File

@ -32,23 +32,27 @@ struct _gncEntry {
char * action;
gnc_numeric quantity;
gnc_numeric price;
gnc_numeric tax;
gint tax_type;
gnc_numeric discount;
gint disc_type;
GncAmountType disc_type;
GncDiscountHow disc_how;
Account * account;
Account * taxaccount;
gboolean taxable;
gboolean taxincluded;
GncTaxTable * tax_table;
GncOrder * order;
GncInvoice * invoice;
gnc_numeric value;
gnc_numeric value_rounded;
GList * tax_values;
gnc_numeric tax_value;
gnc_numeric tax_value_rounded;
gnc_numeric disc_value;
gnc_numeric disc_value_rounded;
gboolean values_dirty;
Timespec taxtable_modtime;
gboolean dirty;
};
@ -70,33 +74,6 @@ struct _gncEntry {
static void addObj (GncEntry *entry);
static void remObj (GncEntry *entry);
static char * typeStrs[] = {
N_("Value"),
N_("Percent"),
N_("Value/Pretax"),
N_("Percent/Pretax")
};
const char *gncEntryGetTaxTypeStr (gint type)
{
return typeStrs[type & 0x01]; /* Only 0, 1 */
}
const char *gncEntryGetDiscountTypeStr (gint type)
{
return typeStrs[type & 0x03]; /* Only 0, 1, 2, 3 */
}
gint gncEntryGetTypeFromStr (const char *type)
{
gint i;
for (i = 0; i < 3; i++)
if (!safe_strcmp (typeStrs[i], type))
return i;
return -1;
}
G_INLINE_FUNC void mark_entry (GncEntry *entry);
G_INLINE_FUNC void
mark_entry (GncEntry *entry)
@ -124,11 +101,11 @@ GncEntry *gncEntryCreate (GNCBook *book)
gnc_numeric zero = gnc_numeric_zero ();
entry->quantity = zero;
entry->price = zero;
entry->tax = zero;
entry->discount = zero;
}
entry->tax_type = GNC_ENTRY_INTERP_PERCENT;
entry->disc_type = GNC_ENTRY_INTERP_PERCENT;
entry->disc_type = GNC_AMT_TYPE_PERCENT;
entry->disc_how = GNC_DISC_PRETAX;
entry->taxable = TRUE;
entry->dirty = FALSE;
entry->values_dirty = TRUE;
@ -148,6 +125,8 @@ void gncEntryDestroy (GncEntry *entry)
CACHE_REMOVE (entry->desc);
CACHE_REMOVE (entry->action);
if (entry->tax_values)
gncAccountValueDestroy (entry->tax_values);
remObj (entry);
g_free (entry);
@ -209,14 +188,6 @@ void gncEntrySetPrice (GncEntry *entry, gnc_numeric price)
mark_entry (entry);
}
void gncEntrySetTax (GncEntry *entry, gnc_numeric tax)
{
if (!entry) return;
entry->tax = tax;
entry->values_dirty = TRUE;
mark_entry (entry);
}
void gncEntrySetDiscount (GncEntry *entry, gnc_numeric discount)
{
if (!entry) return;
@ -232,13 +203,6 @@ void gncEntrySetAccount (GncEntry *entry, Account *acc)
mark_entry (entry);
}
void gncEntrySetTaxAccount (GncEntry *entry, Account *acc)
{
if (!entry) return;
entry->taxaccount = acc;
mark_entry (entry);
}
/* Called from gncOrder when we're added to the Order */
void gncEntrySetOrder (GncEntry *entry, GncOrder *order)
{
@ -259,26 +223,53 @@ void gncEntrySetInvoice (GncEntry *entry, GncInvoice *invoice)
mark_entry (entry);
}
void gncEntrySetTaxType (GncEntry *entry, gint type)
void gncEntrySetTaxable (GncEntry *entry, gboolean taxable)
{
if (!entry) return;
if (type < 0 || type > 1) return;
entry->tax_type = type;
entry->taxable = taxable;
entry->values_dirty = TRUE;
mark_entry (entry);
}
void gncEntrySetDiscountType (GncEntry *entry, gint type)
void gncEntrySetTaxIncluded (GncEntry *entry, gboolean taxincluded)
{
if (!entry) return;
entry->taxincluded = taxincluded;
entry->values_dirty = TRUE;
mark_entry (entry);
}
void gncEntrySetTaxTable (GncEntry *entry, GncTaxTable *table)
{
if (!entry) return;
if (entry->tax_table == table) return;
if (entry->tax_table)
gncTaxTableDecRef (entry->tax_table);
if (table)
gncTaxTableIncRef (table);
entry->tax_table = table;
entry->values_dirty = TRUE;
mark_entry (entry);
}
void gncEntrySetDiscountType (GncEntry *entry, GncAmountType type)
{
if (!entry) return;
if (type < 0 || type > 3) return;
entry->disc_type = type;
entry->values_dirty = TRUE;
mark_entry (entry);
}
void gncEntrySetDiscountHow (GncEntry *entry, GncDiscountHow how)
{
if (!entry) return;
entry->disc_how = how;
entry->values_dirty = TRUE;
mark_entry (entry);
}
void gncEntrySetDirty (GncEntry *entry, gboolean dirty)
{
if (!entry) return;
@ -295,12 +286,14 @@ void gncEntryCopy (const GncEntry *src, GncEntry *dest)
gncEntrySetAction (dest, src->action);
dest->quantity = src->quantity;
dest->price = src->price;
dest->tax = src->tax;
dest->tax_type = src->tax_type;
dest->discount = src->discount;
dest->disc_type = src->disc_type;
dest->account = src->account;
dest->taxaccount = src->taxaccount;
dest->taxable = src->taxable;
dest->taxincluded = src->taxincluded;
if (src->tax_table)
gncEntrySetTaxTable (dest, src->tax_table);
if (src->order)
gncOrderAddEntry (src->order, dest);
@ -363,12 +356,6 @@ gnc_numeric gncEntryGetPrice (GncEntry *entry)
return entry->price;
}
gnc_numeric gncEntryGetTax (GncEntry *entry)
{
if (!entry) return gnc_numeric_zero();
return entry->tax;
}
gnc_numeric gncEntryGetDiscount (GncEntry *entry)
{
if (!entry) return gnc_numeric_zero();
@ -381,12 +368,6 @@ Account * gncEntryGetAccount (GncEntry *entry)
return entry->account;
}
Account * gncEntryGetTaxAccount (GncEntry *entry)
{
if (!entry) return NULL;
return entry->taxaccount;
}
GncInvoice * gncEntryGetInvoice (GncEntry *entry)
{
if (!entry) return NULL;
@ -399,18 +380,36 @@ GncOrder * gncEntryGetOrder (GncEntry *entry)
return entry->order;
}
gint gncEntryGetTaxType (GncEntry *entry)
{
if (!entry) return 0;
return entry->tax_type;
}
gint gncEntryGetDiscountType (GncEntry *entry)
GncAmountType gncEntryGetDiscountType (GncEntry *entry)
{
if (!entry) return 0;
return entry->disc_type;
}
GncDiscountHow gncEntryGetDiscountHow (GncEntry *entry)
{
if (!entry) return 0;
return entry->disc_how;
}
gboolean gncEntryGetTaxable (GncEntry *entry)
{
if (!entry) return FALSE;
return entry->taxable;
}
gboolean gncEntryGetTaxIncluded (GncEntry *entry)
{
if (!entry) return FALSE;
return entry->taxincluded;
}
GncTaxTable * gncEntryGetTaxTable (GncEntry *entry)
{
if (!entry) return NULL;
return entry->tax_table;
}
GncEntry * gncEntryLookup (GNCBook *book, const GUID *guid)
{
if (!book || !guid) return NULL;
@ -418,49 +417,202 @@ GncEntry * gncEntryLookup (GNCBook *book, const GUID *guid)
guid, _GNC_MOD_NAME);
}
/*
* This is the logic of computing the total for an Entry, so you know
* what values to put into various Splits or to display in the ledger.
* In other words, we combine the quantity, unit-price, discount and
* taxes together, depending on various flags.
*
* There are four potental ways to combine these numbers:
* Discount: Pre-Tax Post-Tax
* Tax : Included Not-Included
*
* The process is relatively simple:
*
* 1) compute the agregate price (price*qty)
* 2) if taxincluded, then back-compute the agregate pre-tax price
* 3) apply discount and taxes in the appropriate order
* 4) return the requested results.
*
* step 2 can be done with agregate taxes; no need to compute them all
* unless the caller asked for the tax_value.
*
* Note that the returned "value" is such that value + tax == "total
* to pay," which means in the case of tax-included that the returned
* "value" may be less than the agregate price, even without a
* discount. If you want to display the tax-included value, you need
* to add the value and taxes together. In other words, the value is
* the amount the merchant gets; the taxes are the amount the gov't
* gets, and the customer pays the sum or value + taxes.
*
* The discount return value is just for entertainment -- you may way
* to let a consumer know how much they saved.
*/
void gncEntryComputeValue (gnc_numeric qty, gnc_numeric price,
gnc_numeric tax, gint tax_type,
gnc_numeric discount, gint discount_type,
gnc_numeric *value, gnc_numeric *tax_value,
gnc_numeric *discount_value)
GncTaxTable *tax_table, gboolean tax_included,
gnc_numeric discount, GncAmountType discount_type,
GncDiscountHow discount_how,
gnc_numeric *value, gnc_numeric *discount_value,
GList **tax_value)
{
gnc_numeric subtotal;
gnc_numeric this_value;
gnc_numeric aggregate;
gnc_numeric pretax;
gnc_numeric result;
gnc_numeric tax;
gnc_numeric percent = gnc_numeric_create (100, 1);
gnc_numeric tpercent = gnc_numeric_zero ();
gnc_numeric tvalue = gnc_numeric_zero ();
/* Compute the value */
GList * entries = gncTaxTableGetEntries (tax_table);
GList * node;
subtotal = gnc_numeric_mul (qty, price, GNC_DENOM_AUTO, GNC_DENOM_LCD);
/* Step 1: compute the aggregate price */
if (GNC_ENTRY_INTERP_IS_PERCENT (discount_type)) {
discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
discount = gnc_numeric_mul (subtotal, discount, GNC_DENOM_AUTO,
aggregate = gnc_numeric_mul (qty, price, GNC_DENOM_AUTO, GNC_DENOM_LCD);
/* Step 2: compute the pre-tax aggregate */
/* First, compute the aggregate tpercent and tvalue numbers */
for (node = entries; node; node = node->next) {
GncTaxTableEntry *entry = node->data;
gnc_numeric amount = gncTaxTableEntryGetAmount (entry);
switch (gncTaxTableEntryGetType (entry)) {
case GNC_AMT_TYPE_VALUE:
tvalue = gnc_numeric_add (tvalue, amount, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
break;
case GNC_AMT_TYPE_PERCENT:
tpercent = gnc_numeric_add (tpercent, amount, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
break;
default:
g_warning ("Unknown tax type: %d", gncTaxTableEntryGetType (entry));
}
}
/* now we need to convert from 5% -> .05 */
tpercent = gnc_numeric_div (tpercent, percent, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
/* Next, actually compute the pre-tax aggregate value based on the
* taxincluded flag.
*/
if (tax_table && tax_included) {
/* Back-compute the pre-tax aggregate value.
* We know that aggregate = pretax + pretax*tpercent + tvalue, so
* pretax = (aggregate-tvalue)/(1+tpercent)
*/
pretax = gnc_numeric_sub (aggregate, tvalue, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
pretax = gnc_numeric_div (pretax,
gnc_numeric_add (tpercent,
gnc_numeric_create (1, 1),
GNC_DENOM_AUTO, GNC_DENOM_LCD),
GNC_DENOM_AUTO, GNC_DENOM_LCD);
} else {
pretax = aggregate;
}
this_value = gnc_numeric_sub (subtotal, discount, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
if (discount_type & GNC_ENTRY_PRETAX_FLAG)
subtotal = this_value;
/* Step 3: apply discount and taxes in the appropriate order */
/* Save the discount and value return values */
/*
* There are two ways to apply discounts and taxes. In one way, you
* always compute the discount off the pretax number, and compute
* the taxes off of either the pretax value or "pretax-discount"
* value. In the other way, you always compute the tax on "pretax",
* and compute the discount on either "pretax" or "pretax+taxes".
*
* I don't know which is the "correct" way.
*/
/*
* Type: discount tax
* PRETAX pretax pretax-discount
* SAMETIME pretax pretax
* POSTTAX pretax+tax pretax
*/
switch (discount_how) {
case GNC_DISC_PRETAX:
case GNC_DISC_SAMETIME:
/* compute the discount from pretax */
if (discount_type == GNC_AMT_TYPE_PERCENT) {
discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
discount = gnc_numeric_mul (pretax, discount, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
}
result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_DENOM_LCD);
/* Figure out when to apply the tax, pretax or pretax-discount */
if (discount_how == GNC_DISC_PRETAX)
pretax = result;
break;
case GNC_DISC_POSTTAX:
/* compute discount on pretax+taxes */
if (discount_type == GNC_AMT_TYPE_PERCENT) {
gnc_numeric after_tax;
tax = gnc_numeric_mul (pretax, tpercent, GNC_DENOM_AUTO, GNC_DENOM_LCD);
after_tax = gnc_numeric_add (pretax, tax, GNC_DENOM_AUTO, GNC_DENOM_LCD);
after_tax = gnc_numeric_add (after_tax, tvalue, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
discount = gnc_numeric_mul (after_tax, discount, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
}
result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_DENOM_LCD);
break;
default:
g_warning ("unknown DiscountHow value: %d", discount_how);
}
/* Step 4: return the requested results. */
/* result == amount merchant gets
* discount == amount of discount
* need to compute taxes (based on 'pretax') if the caller wants it.
*/
if (discount_value != NULL)
*discount_value = discount;
if (value != NULL)
*value = this_value;
*value = result;
/* Now... Compute the tax value (if the caller wants it) */
/* Now... Compute the list of tax values (if the caller wants it) */
if (tax_value != NULL) {
if (GNC_ENTRY_INTERP_IS_PERCENT (tax_type)) {
tax = gnc_numeric_div (tax, percent, GNC_DENOM_AUTO, GNC_DENOM_LCD);
tax = gnc_numeric_mul (subtotal, tax, GNC_DENOM_AUTO, GNC_DENOM_LCD);
}
GList * taxes = NULL;
*tax_value = tax;
for (node = entries; node; node = node->next) {
GncTaxTableEntry *entry = node->data;
Account *acc = gncTaxTableEntryGetAccount (entry);
gnc_numeric amount = gncTaxTableEntryGetAmount (entry);
g_return_if_fail (acc);
switch (gncTaxTableEntryGetType (entry)) {
case GNC_AMT_TYPE_VALUE:
taxes = gncAccountValueAdd (taxes, acc, amount);
break;
case GNC_AMT_TYPE_PERCENT:
amount = gnc_numeric_div (amount, percent, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
tax = gnc_numeric_mul (pretax, amount, GNC_DENOM_AUTO, GNC_DENOM_LCD);
taxes = gncAccountValueAdd (taxes, acc, tax);
break;
default:
}
}
*tax_value = taxes;
}
return;
@ -484,36 +636,56 @@ gncEntryRecomputeValues (GncEntry *entry)
{
int denom;
/* See if the tax table changed since we last computed values */
if (entry->tax_table) {
Timespec modtime = gncTaxTableLastModified (entry->tax_table);
if (timespec_cmp (&entry->taxtable_modtime, &modtime)) {
entry->values_dirty = TRUE;
entry->taxtable_modtime = modtime;
}
}
if (!entry->values_dirty)
return;
if (entry->tax_values) {
gncAccountValueDestroy (entry->tax_values);
entry->tax_values = NULL;
}
gncEntryComputeValue (entry->quantity, entry->price,
entry->tax, entry->tax_type,
(entry->taxable ? entry->tax_table : NULL),
entry->taxincluded,
entry->discount, entry->disc_type,
&(entry->value), &(entry->tax_value),
&(entry->disc_value));
entry->disc_how,
&(entry->value), &(entry->disc_value),
&(entry->tax_values));
denom = get_commodity_denom (entry);
entry->value_rounded = gnc_numeric_convert (entry->value, denom,
GNC_RND_ROUND);
entry->tax_value_rounded = gnc_numeric_convert (entry->tax_value, denom,
GNC_RND_ROUND);
entry->disc_value_rounded = gnc_numeric_convert (entry->disc_value, denom,
GNC_RND_ROUND);
entry->tax_value = gncAccountValueTotal (entry->tax_values);
entry->tax_value_rounded = gnc_numeric_convert (entry->tax_value, denom,
GNC_RND_ROUND);
entry->values_dirty = FALSE;
}
void gncEntryGetValue (GncEntry *entry, gnc_numeric *value,
gnc_numeric *tax_value, gnc_numeric *discount_value)
gnc_numeric *discount_value, gnc_numeric *tax_value,
GList **tax_values)
{
if (!entry) return;
gncEntryRecomputeValues (entry);
if (value)
*value = entry->value;
if (tax_value)
*tax_value = entry->tax_value;
if (discount_value)
*discount_value = entry->disc_value;
if (tax_value)
*tax_value = entry->tax_value;
if (tax_values)
*tax_values = entry->tax_values;
}
gnc_numeric gncEntryReturnValue (GncEntry *entry)
@ -530,6 +702,13 @@ gnc_numeric gncEntryReturnTaxValue (GncEntry *entry)
return entry->tax_value_rounded;
}
GList * gncEntryReturnTaxValues (GncEntry *entry)
{
if (!entry) return NULL;
gncEntryRecomputeValues (entry);
return entry->tax_values;
}
gnc_numeric gncEntryReturnDiscountValue (GncEntry *entry)
{
if (!entry) return gnc_numeric_zero();

View File

@ -11,21 +11,26 @@ typedef struct _gncEntry GncEntry;
#include "date.h"
#include "gnc-book.h"
#include "gncTaxTable.h"
#include "gncOrder.h"
#include "gncInvoice.h"
#define GNC_ENTRY_MODULE_NAME "gncEntry"
/* How to interpret the Discount and Tax numbers.. You can interpret
* the as a VALUE or a PERCENT. Similarly, you can set the PRETAX
* bit if you want the discount to be applied before a percentage-tax.
*/
#define GNC_ENTRY_INTERP_VALUE 0x00
#define GNC_ENTRY_INTERP_PERCENT 0x01
#define GNC_ENTRY_PRETAX_FLAG 0x02
#define GNC_ENTRY_INTERP_IS_VALUE(x) (((x)&0x01) == GNC_ENTRY_INTERP_VALUE)
#define GNC_ENTRY_INTERP_IS_PERCENT(x) (((x)&0x01) == GNC_ENTRY_INTERP_PERCENT)
/* How to apply the discount and taxes. There are three distinct ways to
* apply them:
*
* Type: discount tax
* PRETAX pretax pretax-discount
* SAMETIME pretax pretax
* POSTTAX pretax+tax pretax
*/
typedef enum {
GNC_DISC_PRETAX = 1,
GNC_DISC_SAMETIME,
GNC_DISC_POSTTAX
} GncDiscountHow;
/* Create/Destroy Functions */
@ -40,13 +45,14 @@ void gncEntrySetDescription (GncEntry *entry, const char *desc);
void gncEntrySetAction (GncEntry *entry, const char *action);
void gncEntrySetQuantity (GncEntry *entry, gnc_numeric quantity);
void gncEntrySetPrice (GncEntry *entry, gnc_numeric price);
void gncEntrySetTax (GncEntry *entry, gnc_numeric tax);
void gncEntrySetTaxType (GncEntry *entry, gint type);
void gncEntrySetDiscount (GncEntry *entry, gnc_numeric discount);
void gncEntrySetDiscountType (GncEntry *entry, gint type);
void gncEntrySetDiscountType (GncEntry *entry, GncAmountType type);
void gncEntrySetDiscountHow (GncEntry *entry, GncDiscountHow how);
void gncEntrySetTaxable (GncEntry *entry, gboolean taxable);
void gncEntrySetTaxIncluded (GncEntry *entry, gboolean tax_included);
void gncEntrySetTaxTable (GncEntry *entry, GncTaxTable *table);
void gncEntrySetAccount (GncEntry *entry, Account *acc);
void gncEntrySetTaxAccount (GncEntry *entry, Account *acc);
/* Get Functions */
@ -58,35 +64,45 @@ const char * gncEntryGetDescription (GncEntry *entry);
const char * gncEntryGetAction (GncEntry *entry);
gnc_numeric gncEntryGetQuantity (GncEntry *entry);
gnc_numeric gncEntryGetPrice (GncEntry *entry);
gnc_numeric gncEntryGetTax (GncEntry *entry);
gint gncEntryGetTaxType (GncEntry *entry);
const char * gncEntryGetTaxTypeStr (gint type);
gnc_numeric gncEntryGetDiscount (GncEntry *entry);
gint gncEntryGetDiscountType (GncEntry *entry);
const char * gncEntryGetDiscountTypeStr (gint type);
GncAmountType gncEntryGetDiscountType (GncEntry *entry);
GncDiscountHow gncEntryGetDiscountHow (GncEntry *entry);
gboolean gncEntryGetTaxable (GncEntry *entry);
gboolean gncEntryGetTaxIncluded (GncEntry *entry);
GncTaxTable * gncEntryGetTaxTable (GncEntry *entry);
void gncEntryCopy (const GncEntry *src, GncEntry *dest);
/* The first three return the rounded values -- the last returns the
* list of unrounded account-values. The list belongs to the entry
* and will be destroyed, so use it quickly.
*/
gnc_numeric gncEntryReturnValue (GncEntry *entry);
gnc_numeric gncEntryReturnTaxValue (GncEntry *entry);
gnc_numeric gncEntryReturnDiscountValue (GncEntry *entry);
gnc_numeric gncEntryReturnTaxValue (GncEntry *entry);
GList * gncEntryReturnTaxValues (GncEntry *entry);
/* Compute the Entry value, tax-value, and discount_value, based on the
* quantity, price, discount, tax, and discount/tax types. Note that
* the value is the after-discount value.
/* Compute the Entry value, tax-value, and discount_value, based on
* the quantity, price, discount, tax-table, and types. The value is
* the amount the merchant gets, the taxes are what the gov't gets,
* and the discount is how much the customer saved.
*
* The tax_values list is the property of the entry and will be
* destroyed automatically, so use it quickly. Note that all return
* values from these two functions are NOT rounded.
*/
void gncEntryGetValue (GncEntry *entry, gnc_numeric *value,
gnc_numeric *tax_value, gnc_numeric *discount);
gnc_numeric *discount, gnc_numeric *tax_value,
GList **tax_values);
void gncEntryComputeValue (gnc_numeric qty, gnc_numeric price,
gnc_numeric tax, gint tax_type,
gnc_numeric discount, gint discount_type,
gnc_numeric *value, gnc_numeric *tax_value,
gnc_numeric *discount_value);
gint gncEntryGetTypeFromStr (const char *type);
GncTaxTable *tax_table, gboolean tax_included,
gnc_numeric discount, GncAmountType discount_type,
GncDiscountHow discount_how,
/* return values */
gnc_numeric *value, gnc_numeric *discount_value,
GList **tax_values);
Account * gncEntryGetAccount (GncEntry *entry);
Account * gncEntryGetTaxAccount (GncEntry *entry);
GncOrder * gncEntryGetOrder (GncEntry *entry);
GncInvoice * gncEntryGetInvoice (GncEntry *entry);

View File

@ -395,23 +395,6 @@ gncInvoiceAttachInvoiceToTxn (GncInvoice *invoice, Transaction *txn)
gncInvoiceSetPostedTxn (invoice, txn);
}
#define GET_OR_ADD_ACCVAL(list,t_acc,res) { \
GList *li; \
res = NULL; \
for (li = list; li; li = li->next) { \
res = li->data; \
if (res->acc == t_acc) \
break; \
res = NULL; \
} \
if (!res) { \
res = g_new0 (struct acct_val, 1); \
res->acc = t_acc; \
res->val = gnc_numeric_zero (); \
list = g_list_append (list, res); \
} \
}
Transaction * gncInvoicePostToAccount (GncInvoice *invoice, Account *acc,
Timespec *post_date, Timespec *due_date,
const char * memo)
@ -423,10 +406,6 @@ Transaction * gncInvoicePostToAccount (GncInvoice *invoice, Account *acc,
gnc_numeric total;
gboolean reverse;
const char *name;
struct acct_val {
Account * acc;
gnc_numeric val;
} *acc_val;
if (!invoice || !acc) return NULL;
@ -462,57 +441,55 @@ Transaction * gncInvoicePostToAccount (GncInvoice *invoice, Account *acc,
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;
/* Obtain the Entry Value and TaxValue */
gncEntryGetValue (entry, &value, &tax, NULL);
/* Stabilize the TaxTable in this entry */
gncEntrySetTaxTable (entry,
gncTaxTableReturnChild (gncEntryGetTaxTable (entry),
TRUE));
/* Obtain the Entry's Value and TaxValues */
gncEntryGetValue (entry, &value, NULL, &tax, &taxes);
/* add the value for the account split */
this_acc = gncEntryGetAccount (entry);
if (this_acc) {
/* Find the account value for this_acc. If we haven't seen this
* account before, create a new total and add to list
*/
GET_OR_ADD_ACCVAL (splitinfo, this_acc, acc_val);
if (gnc_numeric_check (value) == GNC_ERROR_OK) {
acc_val->val = gnc_numeric_add (acc_val->val, value, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
splitinfo = gncAccountValueAdd (splitinfo, this_acc, value);
total = gnc_numeric_add (total, value, GNC_DENOM_AUTO, GNC_DENOM_LCD);
} else
g_warning ("bad value in our entry");
}
/* Repeat for the TaxValue */
this_acc = gncEntryGetTaxAccount (entry);
if (this_acc) {
/* 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_DENOM_LCD);
else
g_warning ("bad tax in our entry");
GET_OR_ADD_ACCVAL (splitinfo, this_acc, acc_val);
if (gnc_numeric_check (tax) == GNC_ERROR_OK) {
acc_val->val = gnc_numeric_add_fixed (acc_val->val, tax);
total = gnc_numeric_add (total, tax, GNC_DENOM_AUTO, GNC_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;
acc_val = iter->data;
GncAccountValue *acc_val = iter->data;
split = xaccMallocSplit (invoice->book);
/* set action and memo? */
xaccSplitSetMemo (split, memo);
xaccSplitSetBaseValue (split, (reverse ? gnc_numeric_neg (acc_val->val)
: acc_val->val),
xaccSplitSetBaseValue (split, (reverse ? gnc_numeric_neg (acc_val->value)
: acc_val->value),
invoice->common_commodity);
xaccAccountBeginEdit (acc_val->acc);
xaccAccountInsertSplit (acc_val->acc, split);
xaccAccountCommitEdit (acc_val->acc);
xaccAccountBeginEdit (acc_val->account);
xaccAccountInsertSplit (acc_val->account, split);
xaccAccountCommitEdit (acc_val->account);
xaccTransAppendSplit (txn, split);
}
@ -541,6 +518,8 @@ Transaction * gncInvoicePostToAccount (GncInvoice *invoice, Account *acc,
xaccTransCommitEdit (txn);
gncAccountValueDestroy (splitinfo);
return txn;
}

View File

@ -25,6 +25,7 @@ struct _gncTaxTable {
char * name;
GList * entries;
Timespec modtime; /* internal date of last modtime */
gint64 refcount;
GNCBook * book;
GncTaxTable * parent; /* if non-null, we are an immutable child */
@ -36,7 +37,7 @@ struct _gncTaxTable {
struct _gncTaxTableEntry {
GncTaxTable * table;
Account * account;
GncTaxType type;
GncAmountType type;
gnc_numeric amount;
};
@ -72,6 +73,13 @@ mark_table (GncTaxTable *table)
gnc_engine_generate_event (&table->guid, GNC_EVENT_MODIFY);
}
G_INLINE_FUNC void mod_table (GncTaxTable *table);
G_INLINE_FUNC void
mod_table (GncTaxTable *table)
{
timespecFromTime_t (&table->modtime, time(NULL));
}
/* Create/Destroy Functions */
GncTaxTable * gncTaxTableCreate (GNCBook *book)
{
@ -140,6 +148,7 @@ void gncTaxTableSetParent (GncTaxTable *table, GncTaxTable *parent)
{
if (!table) return;
table->parent = parent;
table->refcount = 0;
gncTaxTableMakeInvisible (table);
}
@ -152,14 +161,16 @@ void gncTaxTableSetChild (GncTaxTable *table, GncTaxTable *child)
void gncTaxTableIncRef (GncTaxTable *table)
{
if (!table) return;
if (table->parent) return; /* children dont need refcounts */
table->refcount++;
}
void gncTaxTableDecRef (GncTaxTable *table)
{
if (!table) return;
if (table->parent) return; /* children dont need refcounts */
table->refcount--;
g_return_if_fail (table->refcount < 0);
g_return_if_fail (table->refcount >= 0);
}
void gncTaxTableSetRefcount (GncTaxTable *table, gint64 refcount)
@ -180,17 +191,21 @@ void gncTaxTableEntrySetAccount (GncTaxTableEntry *entry, Account *account)
if (!entry || !account) return;
if (entry->account == account) return;
entry->account = account;
if (entry->table)
if (entry->table) {
mark_table (entry->table);
mod_table (entry->table);
}
}
void gncTaxTableEntrySetType (GncTaxTableEntry *entry, GncTaxType type)
void gncTaxTableEntrySetType (GncTaxTableEntry *entry, GncAmountType type)
{
if (!entry) return;
if (entry->type == type) return;
entry->type = type;
if (entry->table)
if (entry->table) {
mark_table (entry->table);
mod_table (entry->table);
}
}
void gncTaxTableEntrySetAmount (GncTaxTableEntry *entry, gnc_numeric amount)
@ -198,8 +213,10 @@ void gncTaxTableEntrySetAmount (GncTaxTableEntry *entry, gnc_numeric amount)
if (!entry) return;
if (gnc_numeric_eq (entry->amount, amount)) return;
entry->amount = amount;
if (entry->table)
if (entry->table) {
mark_table (entry->table);
mod_table (entry->table);
}
}
void gncTaxTableAddEntry (GncTaxTable *table, GncTaxTableEntry *entry)
@ -213,6 +230,7 @@ void gncTaxTableAddEntry (GncTaxTable *table, GncTaxTableEntry *entry)
table->entries = g_list_insert_sorted (table->entries, entry,
(GCompareFunc)gncTaxTableEntryCompare);
mark_table (table);
mod_table (table);
}
void gncTaxTableRemoveEntry (GncTaxTable *table, GncTaxTableEntry *entry)
@ -221,6 +239,7 @@ void gncTaxTableRemoveEntry (GncTaxTable *table, GncTaxTableEntry *entry)
entry->table = NULL;
table->entries = g_list_remove (table->entries, entry);
mark_table (table);
mod_table (table);
}
void gncTaxTableChanged (GncTaxTable *table)
@ -344,6 +363,13 @@ gint64 gncTaxTableGetRefcount (GncTaxTable *table)
return table->refcount;
}
Timespec gncTaxTableLastModified (GncTaxTable *table)
{
Timespec ts = { 0 , 0 };
if (!table) return ts;
return table->modtime;
}
gboolean gncTaxTableGetInvisible (GncTaxTable *table)
{
if (!table) return FALSE;
@ -356,9 +382,9 @@ Account * gncTaxTableEntryGetAccount (GncTaxTableEntry *entry)
return entry->account;
}
GncTaxType gncTaxTableEntryGetType (GncTaxTableEntry *entry)
GncAmountType gncTaxTableEntryGetType (GncTaxTableEntry *entry)
{
if (!entry) return GNC_TAX_TYPE_NONE;
if (!entry) return 0;
return entry->type;
}
@ -398,6 +424,72 @@ int gncTaxTableCompare (GncTaxTable *a, GncTaxTable *b)
return safe_strcmp (a->name, b->name);
}
/*
* This will add value to the account-value for acc, creating a new
* list object if necessary
*/
GList *gncAccountValueAdd (GList *list, Account *acc, gnc_numeric value)
{
GList *li;
GncAccountValue *res = NULL;
g_return_val_if_fail (acc, list);
g_return_val_if_fail (gnc_numeric_check (value) == GNC_ERROR_OK, list);
/* Try to find the account in the list */
for (li = list; li; li = li->next) {
res = li->data;
if (res->account == acc) {
res->value = gnc_numeric_add (res->value, value, GNC_DENOM_AUTO,
GNC_DENOM_LCD);
return list;
}
}
/* Nope, didn't find it. */
res = g_new0 (GncAccountValue, 1);
res->account = acc;
res->value = value;
return g_list_prepend (list, res);
}
/* Merge l2 into l1. l2 is not touched. */
GList *gncAccountValueAddList (GList *l1, GList *l2)
{
GList *li;
for (li = l2; li; li = li->next ) {
GncAccountValue *val = li->data;
l1 = gncAccountValueAdd (l1, val->account, val->value);
}
return l1;
}
/* return the total for this list */
gnc_numeric gncAccountValueTotal (GList *list)
{
gnc_numeric total = gnc_numeric_zero ();
for ( ; list ; list = list->next) {
GncAccountValue *val = list->data;
total = gnc_numeric_add (total, val->value, GNC_DENOM_AUTO, GNC_DENOM_LCD);
}
return total;
}
/* Destroy a list of accountvalues */
void gncAccountValueDestroy (GList *list)
{
GList *node;
for ( node = list; node ; node = node->next)
g_free (node->data);
g_list_free (list);
}
/* Package-Private functions */
static void add_or_rem_object (GncTaxTable *table, gboolean add)

View File

@ -9,9 +9,11 @@
typedef struct _gncTaxTable GncTaxTable;
typedef struct _gncTaxTableEntry GncTaxTableEntry;
typedef struct _gncAccountValue GncAccountValue;
#include "gnc-numeric.h"
#include "gnc-book.h"
#include "date.h"
#include "Account.h"
#define GNC_TAXTABLE_MODULE_NAME "gncTaxTable"
@ -21,10 +23,9 @@ typedef struct _gncTaxTableEntry GncTaxTableEntry;
* You can interpret it as a VALUE or a PERCENT.
*/
typedef enum {
GNC_TAX_TYPE_VALUE = 0,
GNC_TAX_TYPE_PERCENT = 1,
GNC_TAX_TYPE_NONE = 2,
} GncTaxType;
GNC_AMT_TYPE_VALUE = 1,
GNC_AMT_TYPE_PERCENT
} GncAmountType;
/* Create/Destroy Functions */
GncTaxTable * gncTaxTableCreate (GNCBook *book);
@ -38,7 +39,7 @@ void gncTaxTableIncRef (GncTaxTable *table);
void gncTaxTableDecRef (GncTaxTable *table);
void gncTaxTableEntrySetAccount (GncTaxTableEntry *entry, Account *account);
void gncTaxTableEntrySetType (GncTaxTableEntry *entry, GncTaxType type);
void gncTaxTableEntrySetType (GncTaxTableEntry *entry, GncAmountType type);
void gncTaxTableEntrySetAmount (GncTaxTableEntry *entry, gnc_numeric amount);
void gncTaxTableAddEntry (GncTaxTable *table, GncTaxTableEntry *entry);
@ -60,12 +61,37 @@ GncTaxTable *gncTaxTableReturnChild (GncTaxTable *table, gboolean make_new);
#define gncTaxTableGetChild(t) gncTaxTableReturnChild((t),FALSE)
GList *gncTaxTableGetEntries (GncTaxTable *table);
gint64 gncTaxTableGetRefcount (GncTaxTable *table);
Timespec gncTaxTableLastModified (GncTaxTable *table);
Account * gncTaxTableEntryGetAccount (GncTaxTableEntry *entry);
GncTaxType gncTaxTableEntryGetType (GncTaxTableEntry *entry);
GncAmountType gncTaxTableEntryGetType (GncTaxTableEntry *entry);
gnc_numeric gncTaxTableEntryGetAmount (GncTaxTableEntry *entry);
int gncTaxTableCompare (GncTaxTable *a, GncTaxTable *b);
int gncTaxTableEntryCompare (GncTaxTableEntry *a, GncTaxTableEntry *b);
/************************************************/
struct _gncAccountValue {
Account * account;
gnc_numeric value;
};
/*
* This will add value to the account-value for acc, creating a new
* list object if necessary
*/
GList *gncAccountValueAdd (GList *list, Account *acc, gnc_numeric value);
/* Merge l2 into l1. l2 is not touched. */
GList *gncAccountValueAddList (GList *l1, GList *l2);
/* return the total for this list */
gnc_numeric gncAccountValueTotal (GList *list);
/* Destroy a list of accountvalues */
void gncAccountValueDestroy (GList *list);
#endif /* GNC_TAXTABLE_H_ */

View File

@ -335,30 +335,6 @@
'((<gnc:GncEntry*> entry))
"Return the Entry's Price")
(gw:wrap-function
ws
'gnc:entry-get-tax
'<gnc:numeric>
"gncEntryGetTax"
'((<gnc:GncEntry*> entry))
"Return the Entry's Tax")
(gw:wrap-function
ws
'gnc:entry-get-tax-type
'<gw:int>
"gncEntryGetTaxType"
'((<gnc:GncEntry*> entry))
"Return the Entry's tax type")
(gw:wrap-function
ws
'gnc:entry-get-tax-type-string
'(<gw:mchars> callee-owned const)
"gncEntryGetTaxTypeStr"
'((<gw:int> tax-type))
"Return the Entry's Tax Type String")
(gw:wrap-function
ws
'gnc:entry-get-discount
@ -375,14 +351,6 @@
'((<gnc:GncEntry*> entry))
"Return the Entry's discount type")
(gw:wrap-function
ws
'gnc:entry-get-discount-type-string
'(<gw:mchars> callee-owned const)
"gncEntryGetDiscountTypeStr"
'((<gw:int> discount-type))
"Return the Entry's Discount Type String")
(gw:wrap-function
ws
'gnc:entry-get-value

View File

@ -88,7 +88,7 @@ new_tax_table_ok_cb (GtkWidget *widget, gpointer data)
gnc_error_dialog_parented (GTK_WINDOW (ntt->dialog), message);
return;
}
if (ntt->type == GNC_TAX_TYPE_PERCENT &&
if (ntt->type == GNC_AMT_TYPE_PERCENT &&
gnc_numeric_compare (amount,
gnc_numeric_create (100, 1)) > 0) {
message = _("Percentage amount must be between 0 and 100.");
@ -185,15 +185,15 @@ static GtkWidget *
make_menu (GtkWidget *omenu, NewTaxTable *ntt)
{
GtkWidget *menu, *value, *percent;
int current = ntt->type;
int current = ntt->type - 1;
menu = gtk_menu_new ();
value= add_menu_item (menu, ntt, _("Value $"), GNC_TAX_TYPE_VALUE);
percent = add_menu_item (menu, ntt, _("Percent %"), GNC_TAX_TYPE_PERCENT);
value = add_menu_item (menu, ntt, _("Value $"), GNC_AMT_TYPE_VALUE);
percent = add_menu_item (menu, ntt, _("Percent %"), GNC_AMT_TYPE_PERCENT);
gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
gtk_signal_emit_by_name (GTK_OBJECT ((current == GNC_TAX_TYPE_VALUE ?
gtk_signal_emit_by_name (GTK_OBJECT ((current == GNC_AMT_TYPE_VALUE-1 ?
value : percent)), "activate", ntt);
gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), current);
return menu;
@ -218,7 +218,7 @@ new_tax_table_dialog (TaxTableWindow *ttw, gboolean new_table,
if (entry)
ntt->type = gncTaxTableEntryGetType (entry);
else
ntt->type = GNC_TAX_TYPE_PERCENT;
ntt->type = GNC_AMT_TYPE_PERCENT;
/* Open and read the XML */
xml = gnc_glade_xml_new ("tax-tables.glade", "New Tax Table Dialog");
@ -232,6 +232,7 @@ new_tax_table_dialog (TaxTableWindow *ttw, gboolean new_table,
box = glade_xml_get_widget (xml, "amount_box");
ntt->amount_entry = widget = gnc_amount_edit_new ();
gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (widget), TRUE);
gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (widget), 100000);
gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 0);
box = glade_xml_get_widget (xml, "account_frame");
@ -320,7 +321,7 @@ tax_table_entries_refresh (TaxTableWindow *ttw, gboolean new_table)
row_text[0] = xaccAccountGetFullName (acc, gnc_get_account_separator ());
switch (gncTaxTableEntryGetType (entry)) {
case GNC_TAX_TYPE_PERCENT:
case GNC_AMT_TYPE_PERCENT:
row_text[1] =
g_strdup_printf ("%s%%",
xaccPrintAmount (amount,

View File

@ -65,6 +65,35 @@ Account * gnc_entry_ledger_get_account (GncEntryLedger *ledger,
gnc_get_account_separator ());
}
GncTaxTable * gnc_entry_ledger_get_taxtable (GncEntryLedger *ledger,
const char *cell_name)
{
const char * name =
gnc_table_layout_get_cell_value (ledger->table->layout, cell_name);
return gncTaxTableLookupByName (ledger->book, name);
}
gboolean gnc_entry_ledger_get_checkmark (GncEntryLedger *ledger,
const char * cell_name)
{
const char *value =
gnc_table_layout_get_cell_value (ledger->table->layout, cell_name);
if (!value || *value == '\0')
return FALSE;
switch (*value) {
case 'X':
return TRUE;
case ' ':
return FALSE;
default:
g_warning ("Invalid checkmark character: %d", *value);
return FALSE;
}
}
char gnc_entry_ledger_get_inv (GncEntryLedger *ledger, const char * cell_name)
{
const char *value =
@ -159,11 +188,6 @@ gnc_entry_ledger_config_cells (GncEntryLedger *ledger)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISC_CELL),
1000000);
gnc_price_cell_set_fraction
((PriceCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAX_CELL),
1000000);
gnc_price_cell_set_fraction
((PriceCell *) gnc_table_layout_get_cell (ledger->table->layout,
ENTRY_QTY_CELL),
@ -440,26 +464,44 @@ void
gnc_entry_ledger_compute_value (GncEntryLedger *ledger,
gnc_numeric *value, gnc_numeric *tax_value)
{
gnc_numeric qty, price, discount, tax;
gint disc_type, tax_type;
gnc_numeric qty, price, discount;
gint disc_type, disc_how;
gboolean taxable, taxincluded;
GncTaxTable *table;
GList *taxes = NULL;
gnc_entry_ledger_get_numeric (ledger, ENTRY_QTY_CELL, &qty);
gnc_entry_ledger_get_numeric (ledger, ENTRY_PRIC_CELL, &price);
gnc_entry_ledger_get_numeric (ledger, ENTRY_DISC_CELL, &discount);
gnc_entry_ledger_get_numeric (ledger, ENTRY_TAX_CELL, &tax);
disc_type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);
tax_type = gnc_entry_ledger_get_type (ledger, ENTRY_TAXTYPE_CELL);
disc_how = gnc_entry_ledger_get_type (ledger, ENTRY_DISHOW_CELL);
gncEntryComputeValue (qty, price, tax, tax_type, discount, disc_type,
value, tax_value, NULL);
/* If we're so early in the process that we don't have info, stop now */
if (disc_type < 0 || disc_how < 0) {
if (value)
*value = gnc_numeric_zero ();
if (tax_value)
*tax_value = gnc_numeric_zero ();
return;
}
taxable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
taxincluded = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXINCLUDED_CELL);
table = gnc_entry_ledger_get_taxtable (ledger, ENTRY_TAXTABLE_CELL);
gncEntryComputeValue (qty, price, (taxable ? table : NULL), taxincluded,
discount, disc_type, disc_how,
value, NULL, &taxes);
/* Now convert the values to the proper denomination */
if (value)
*value = gnc_numeric_convert (*value, 100 /* XXX */, GNC_RND_ROUND);
if (tax_value)
if (tax_value) {
*tax_value = gncAccountValueTotal (taxes);
*tax_value = gnc_numeric_convert (*tax_value, 100 /* XXX */, GNC_RND_ROUND);
}
}
gboolean

View File

@ -37,11 +37,12 @@ typedef struct entry_ledger_colors
#define ENTRY_DESC_CELL "description"
#define ENTRY_DISC_CELL "discount"
#define ENTRY_DISTYPE_CELL "discount-type"
#define ENTRY_DISHOW_CELL "discount-how"
#define ENTRY_PRIC_CELL "price"
#define ENTRY_QTY_CELL "quantity"
#define ENTRY_TAXACC_CELL "tax-account"
#define ENTRY_TAXTYPE_CELL "tax-type"
#define ENTRY_TAX_CELL "tax"
#define ENTRY_TAXABLE_CELL "taxable"
#define ENTRY_TAXTABLE_CELL "taxtable"
#define ENTRY_TAXINCLUDED_CELL "taxincluded"
#define ENTRY_INV_CELL "invoiced-p"
#define ENTRY_VALUE_CELL "line-value"

View File

@ -125,10 +125,10 @@ gnc_entry_ledger_verify_acc_cell_ok (GncEntryLedger *ledger,
static gboolean
gnc_entry_ledger_verify_can_save (GncEntryLedger *ledger)
{
gnc_numeric value, tax_value;
gnc_numeric value;
/* Compute the value and tax value of the current cursor */
gnc_entry_ledger_compute_value (ledger, &value, &tax_value);
gnc_entry_ledger_compute_value (ledger, &value, NULL);
/* If there is a value, make sure there is an account */
if (! gnc_numeric_zero_p (value)) {
@ -137,13 +137,6 @@ gnc_entry_ledger_verify_can_save (GncEntryLedger *ledger)
return FALSE;
}
/* If there is a tax value, make sure there is a tax account */
if (! gnc_numeric_zero_p (tax_value)) {
if (!gnc_entry_ledger_verify_acc_cell_ok (ledger, ENTRY_TAXACC_CELL,
_("a Tax Account")))
return FALSE;
}
return TRUE;
}
@ -260,35 +253,22 @@ static gboolean gnc_entry_ledger_traverse (VirtualLocation *p_new_virt_loc,
cell_name = gnc_table_get_current_cell_name (ledger->table);
/* See if we are leaving an account field */
/* See if we are leaving the account field */
do
{
ComboCell *cell;
Account *account;
char *name;
if (!gnc_cell_name_equal (cell_name, ENTRY_ACCT_CELL) &&
!gnc_cell_name_equal (cell_name, ENTRY_TAXACC_CELL))
if (!gnc_cell_name_equal (cell_name, ENTRY_ACCT_CELL))
break;
cell = NULL;
if (gnc_cell_name_equal (cell_name, ENTRY_ACCT_CELL))
{
if (gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_ACCT_CELL, FALSE))
cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
ENTRY_ACCT_CELL);
}
if (gnc_cell_name_equal (cell_name, ENTRY_TAXACC_CELL))
{
if (gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_TAXACC_CELL, FALSE))
cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
ENTRY_TAXACC_CELL);
}
if (!gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_ACCT_CELL, FALSE))
break;
cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
ENTRY_ACCT_CELL);
if (!cell)
break;
@ -296,7 +276,7 @@ static gboolean gnc_entry_ledger_traverse (VirtualLocation *p_new_virt_loc,
if (!name || *name == '\0')
break;
account = xaccGetAccountFromFullName (gnc_get_current_group (),
account = xaccGetAccountFromFullName (gnc_book_get_group (ledger->book),
cell->cell.value,
gnc_get_account_separator ());
if (account)
@ -325,6 +305,55 @@ static gboolean gnc_entry_ledger_traverse (VirtualLocation *p_new_virt_loc,
} while (FALSE);
/* See if we are leaving the TaxTable field */
do
{
ComboCell *cell;
GncTaxTable *table;
char *name;
if (!gnc_cell_name_equal (cell_name, ENTRY_TAXTABLE_CELL))
break;
if (!gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_TAXTABLE_CELL, FALSE))
break;
cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
ENTRY_TAXTABLE_CELL);
if (!cell)
break;
name = cell->cell.value;
if (!name || *name == '\0')
break;
table = gncTaxTableLookupByName (ledger->book, cell->cell.value);
if (table)
break;
{
const char *format = _("The tax table %s does not exist.\n"
"Would you like to create it?");
if (!gnc_verify_dialog_parented (ledger->parent, TRUE, format, name))
break;
}
ledger->full_refresh = FALSE;
// table = gnc_ui_new_tax_table_from_name (name); XXX
if (!table)
break;
ledger->full_refresh = TRUE;
name = (char *)gncTaxTableGetName (table);
gnc_combo_cell_set_value (cell, name);
gnc_basic_cell_set_changed (&cell->cell, TRUE);
} while (FALSE);
/* See if we are tabbing off the end of the very last line
* (i.e. the blank entry)
*/

View File

@ -51,6 +51,8 @@ static void gnc_entry_ledger_layout_add_cells (GncEntryLedger *ledger,
gboolean expandable;
gboolean span;
} cells[] = {
{ ENTRY_INV_CELL, RECN_CELL_TYPE_NAME, N_("sample:X")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_DATE_CELL, DATE_CELL_TYPE_NAME, N_("sample:12/12/2000")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_DESC_CELL, QUICKFILL_CELL_TYPE_NAME,
@ -62,19 +64,19 @@ static void gnc_entry_ledger_layout_add_cells (GncEntryLedger *ledger,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_PRIC_CELL, PRICE_CELL_TYPE_NAME, N_("sample:999,999.00") + 7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_TAX_CELL, PRICE_CELL_TYPE_NAME, N_("sample:9,999.00") + 7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_DISC_CELL, PRICE_CELL_TYPE_NAME, N_("sample:9,999.00") + 7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_ACCT_CELL, COMBO_CELL_TYPE_NAME, N_("sample:Xfer:Account")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_TAXACC_CELL, COMBO_CELL_TYPE_NAME, N_("sample:Tax:Account")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_TAXTYPE_CELL, RECN_CELL_TYPE_NAME, N_("sample:TT")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_DISTYPE_CELL, RECN_CELL_TYPE_NAME, N_("sample(DT):+%")+11,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_INV_CELL, RECN_CELL_TYPE_NAME, N_("sample:X")+7,
{ ENTRY_DISHOW_CELL, RECN_CELL_TYPE_NAME, N_("sample(DH):+%")+11,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_ACCT_CELL, COMBO_CELL_TYPE_NAME, N_("sample:Xfer:Account")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_TAXABLE_CELL, RECN_CELL_TYPE_NAME, N_("sample:T?")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_TAXINCLUDED_CELL, RECN_CELL_TYPE_NAME, N_("sample:TI")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_TAXTABLE_CELL, COMBO_CELL_TYPE_NAME, N_("sample:Tax Table 1")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
{ ENTRY_VALUE_CELL, PRICE_CELL_TYPE_NAME, N_("sample:999,999.00")+7,
CELL_ALIGN_RIGHT, FALSE, FALSE },
@ -100,7 +102,7 @@ static void gnc_entry_ledger_layout_add_cursors (GncEntryLedger *ledger,
case GNCENTRY_ORDER_VIEWER:
case GNCENTRY_INVOICE_ENTRY:
case GNCENTRY_INVOICE_VIEWER:
num_cols = 14;
num_cols = 15;
break;
default:
g_assert (FALSE);
@ -119,7 +121,6 @@ static void gnc_entry_ledger_set_cells (GncEntryLedger *ledger,
TableLayout *layout)
{
CellBlock *curs;
int x = 0;
switch (ledger->type) {
case GNCENTRY_ORDER_ENTRY:
@ -128,20 +129,21 @@ static void gnc_entry_ledger_set_cells (GncEntryLedger *ledger,
case GNCENTRY_INVOICE_VIEWER:
curs = gnc_table_layout_get_cursor (layout, "cursor");
gnc_table_layout_set_cell (layout, curs, ENTRY_INV_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_DATE_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_DESC_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_ACTN_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_ACCT_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_QTY_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_PRIC_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_DISTYPE_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_DISC_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_TAXTYPE_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_TAX_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_TAXACC_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_VALUE_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_TAXVAL_CELL, 0, x++);
gnc_table_layout_set_cell (layout, curs, ENTRY_INV_CELL, 0, 0);
gnc_table_layout_set_cell (layout, curs, ENTRY_DATE_CELL, 0, 1);
gnc_table_layout_set_cell (layout, curs, ENTRY_DESC_CELL, 0, 2);
gnc_table_layout_set_cell (layout, curs, ENTRY_ACTN_CELL, 0, 3);
gnc_table_layout_set_cell (layout, curs, ENTRY_ACCT_CELL, 0, 4);
gnc_table_layout_set_cell (layout, curs, ENTRY_QTY_CELL, 0, 5);
gnc_table_layout_set_cell (layout, curs, ENTRY_PRIC_CELL, 0, 6);
gnc_table_layout_set_cell (layout, curs, ENTRY_DISTYPE_CELL, 0, 7);
gnc_table_layout_set_cell (layout, curs, ENTRY_DISHOW_CELL, 0, 8);
gnc_table_layout_set_cell (layout, curs, ENTRY_DISC_CELL, 0, 9);
gnc_table_layout_set_cell (layout, curs, ENTRY_TAXABLE_CELL, 0, 10);
gnc_table_layout_set_cell (layout, curs, ENTRY_TAXINCLUDED_CELL, 0, 11);
gnc_table_layout_set_cell (layout, curs, ENTRY_TAXTABLE_CELL, 0, 12);
gnc_table_layout_set_cell (layout, curs, ENTRY_VALUE_CELL, 0, 13);
gnc_table_layout_set_cell (layout, curs, ENTRY_TAXVAL_CELL, 0, 14);
break;

View File

@ -25,29 +25,22 @@
const char * gnc_entry_ledger_type_string_getter (char flag)
{
switch (flag) {
case '0': return _("$");
case '1': return _("%");
case '2': return _("+$");
case '3': return _("+%");
case '1': return _("$");
case '2': return _("%");
default:
return "?";
};
}
static void load_tax_type_cells (GncEntryLedger *ledger)
const char * gnc_entry_ledger_how_string_getter (char flag)
{
RecnCell *cell;
if (!ledger) return;
cell = (RecnCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTYPE_CELL);
if (!cell) return;
gnc_recn_cell_set_valid_flags (cell, "01", '1');
gnc_recn_cell_set_flag_order (cell, "01");
gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_type_string_getter);
switch (flag) {
case '1': return _("<");
case '2': return _("=");
case '3': return _(">");
default:
return "?";
};
}
static void load_discount_type_cells (GncEntryLedger *ledger)
@ -61,23 +54,40 @@ static void load_discount_type_cells (GncEntryLedger *ledger)
if (!cell) return;
gnc_recn_cell_set_valid_flags (cell, "0123", '1');
gnc_recn_cell_set_flag_order (cell, "1032");
gnc_recn_cell_set_valid_flags (cell, "12", '2');
gnc_recn_cell_set_flag_order (cell, "21");
gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_type_string_getter);
}
static void load_inv_type_cells (GncEntryLedger *ledger)
static void load_discount_how_cells (GncEntryLedger *ledger)
{
RecnCell *cell;
if (!ledger) return;
cell = (RecnCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_INV_CELL);
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISHOW_CELL);
if (!cell) return;
gnc_recn_cell_set_valid_flags (cell, " X", ' ');
gnc_recn_cell_set_valid_flags (cell, "123", '1');
gnc_recn_cell_set_flag_order (cell, "123");
gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_how_string_getter);
}
static void load_inv_type_cells (GncEntryLedger *ledger, char *cell_name,
gboolean default_is_true)
{
RecnCell *cell;
if (!ledger) return;
cell = (RecnCell *)
gnc_table_layout_get_cell (ledger->table->layout, cell_name);
if (!cell) return;
gnc_recn_cell_set_valid_flags (cell, " X", (default_is_true ? 'X' : ' '));
gnc_recn_cell_set_flag_order (cell, " X");
}
@ -119,16 +129,30 @@ static void load_xfer_type_cells (GncEntryLedger *ledger)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_ACCT_CELL);
gnc_combo_cell_clear_menu (cell);
load_xfer_cell (cell, group);
}
static void load_taxtable_type_cells (GncEntryLedger *ledger)
{
GList *list;
ComboCell *cell;
cell = (ComboCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXACC_CELL);
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTABLE_CELL);
gnc_combo_cell_clear_menu (cell);
load_xfer_cell (cell, group);
list = gncTaxTableGetTables (ledger->book);
for ( ; list ; list = list->next ) {
GncTaxTable *table = list->data;
const char *name = gncTaxTableGetName (table);
if (name != NULL)
gnc_combo_cell_add_menu_item (cell, (char*)name);
}
}
void gnc_entry_ledger_load_xfer_cells (GncEntryLedger *ledger)
{
load_xfer_type_cells (ledger);
load_taxtable_type_cells (ledger);
}
/* XXX (FIXME): This should be in a config file! */
@ -152,9 +176,11 @@ void gnc_entry_ledger_load (GncEntryLedger *ledger, GList *entry_list)
/* Load up cells */
load_discount_type_cells (ledger);
load_tax_type_cells (ledger);
load_inv_type_cells (ledger);
load_xfer_type_cells (ledger);
load_discount_how_cells (ledger);
load_inv_type_cells (ledger, ENTRY_INV_CELL, FALSE);
load_inv_type_cells (ledger, ENTRY_TAXABLE_CELL, TRUE);
load_inv_type_cells (ledger, ENTRY_TAXINCLUDED_CELL, FALSE);
gnc_entry_ledger_load_xfer_cells (ledger);
blank_entry = gnc_entry_ledger_get_blank_entry (ledger);

View File

@ -63,6 +63,11 @@ static const char * get_distype_label (VirtualLocation virt_loc, gpointer data)
return _("DT");
}
static const char * get_dishow_label (VirtualLocation virt_loc, gpointer data)
{
return _("DH");
}
static const char * get_pric_label (VirtualLocation virt_loc, gpointer data)
{
return _("Unit Price");
@ -73,19 +78,19 @@ static const char * get_qty_label (VirtualLocation virt_loc, gpointer data)
return _("Quantity");
}
static const char * get_taxacc_label (VirtualLocation virt_loc, gpointer data)
static const char * get_taxtable_label (VirtualLocation virt_loc, gpointer data)
{
return _("Tax Account");
return _("Tax Table");
}
static const char * get_taxtype_label (VirtualLocation virt_loc, gpointer data)
static const char * get_taxable_label (VirtualLocation virt_loc, gpointer data)
{
return _("TT");
return _("T?");
}
static const char * get_tax_label (VirtualLocation virt_loc, gpointer data)
static const char * get_taxincluded_label (VirtualLocation virt_loc, gpointer data)
{
return _("Tax");
return _("TI");
}
static const char * get_inv_label (VirtualLocation virt_loc, gpointer data)
@ -201,6 +206,28 @@ static const char * get_distype_entry (VirtualLocation virt_loc,
}
}
static const char * get_dishow_entry (VirtualLocation virt_loc,
gboolean translate,
gboolean *conditionally_changed,
gpointer user_data)
{
GncEntryLedger *ledger = user_data;
GncEntry *entry;
char type;
entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
type = gncEntryGetDiscountHow (entry);
if (translate) {
return gnc_entry_ledger_how_string_getter (type + '0');
} else {
static char s[2];
s[0] = '0' + type;
s[1] = '\0';
return s;
}
}
static const char * get_pric_entry (VirtualLocation virt_loc,
gboolean translate,
gboolean *conditionally_changed,
@ -237,62 +264,98 @@ static const char * get_qty_entry (VirtualLocation virt_loc,
return xaccPrintAmount (qty, gnc_default_print_info (FALSE));
}
static const char * get_taxacc_entry (VirtualLocation virt_loc,
static const char * get_taxable_entry (VirtualLocation virt_loc,
gboolean translate,
gboolean *conditionally_changed,
gpointer user_data)
{
char * name = NULL;
GncEntryLedger *ledger = user_data;
GncEntry *entry;
static char s[2] = { ' ', '\0' };
entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
if (gncEntryGetTaxable (entry))
s[0] = 'X';
else
s[0] = ' ';
g_free (name);
name = xaccAccountGetFullName (gncEntryGetTaxAccount (entry),
gnc_get_account_separator ());
return name;
return s;
}
static const char * get_taxtype_entry (VirtualLocation virt_loc,
static gboolean
gnc_entry_ledger_get_taxable_value (VirtualLocation virt_loc,
gboolean translate,
gboolean *conditionally_changed,
gpointer user_data)
{
GncEntryLedger *ledger = user_data;
GncEntry *entry;
char type;
gboolean is_current;
entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
type = gncEntryGetTaxType (entry);
if (translate) {
return gnc_entry_ledger_type_string_getter (type + '0');
} else {
static char s[2];
s[0] = '0' + type;
s[1] = '\0';
return s;
is_current = virt_cell_loc_equal(ledger->table->current_cursor_loc.vcell_loc,
virt_loc.vcell_loc);
if (is_current)
return gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
else {
const char *valstr =
get_taxable_entry (virt_loc, translate, conditionally_changed,
user_data);
if (valstr && *valstr == 'X')
return TRUE;
}
return FALSE;
}
static const char * get_tax_entry (VirtualLocation virt_loc,
static const char * get_taxtable_entry (VirtualLocation virt_loc,
gboolean translate,
gboolean *conditionally_changed,
gpointer user_data)
{
GncEntryLedger *ledger = user_data;
GncEntry *entry;
gnc_numeric tax;
GncTaxTable *table;
gboolean taxable;
/* load the cell properly; just shadow the value */
if (!conditionally_changed) {
taxable = gnc_entry_ledger_get_taxable_value (virt_loc, translate,
conditionally_changed,
user_data);
if (!taxable)
return NULL;
}
entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
tax = gncEntryGetTax (entry);
table = gncEntryGetTaxTable (entry);
return gncTaxTableGetName (table);
}
if (gnc_numeric_zero_p (tax))
return NULL;
static const char * get_taxincluded_entry (VirtualLocation virt_loc,
gboolean translate,
gboolean *conditionally_changed,
gpointer user_data)
{
GncEntryLedger *ledger = user_data;
GncEntry *entry;
static char s[2] = { ' ', '\0' };
gboolean taxable;
return xaccPrintAmount (tax, gnc_default_print_info (FALSE));
/* load the cell properly; just shadow the value */
if (!conditionally_changed) {
taxable = gnc_entry_ledger_get_taxable_value (virt_loc, translate,
conditionally_changed,
user_data);
if (!taxable)
return NULL;
}
entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
if (gncEntryGetTaxIncluded (entry))
s[0] = 'X';
else
s[0] = ' ';
return s;
}
static const char * get_inv_entry (VirtualLocation virt_loc,
@ -433,14 +496,21 @@ static char * get_disc_help (VirtualLocation virt_loc, gpointer user_data)
{
GncEntryLedger *ledger = user_data;
const char *help;
GncEntry *entry;
gint type;
entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);
if (GNC_ENTRY_INTERP_IS_VALUE (gncEntryGetDiscountType (entry)))
switch (type) {
case GNC_AMT_TYPE_VALUE:
help = _("Enter the Discount Amount");
else
break;
case GNC_AMT_TYPE_PERCENT:
help = _("Enter the Discount Percent");
break;
default:
help = _("Enter the Discount ... unknown type");
break;
}
return g_strdup (help);
}
@ -454,18 +524,12 @@ static char * get_distype_help (VirtualLocation virt_loc, gpointer user_data)
type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);
switch (type) {
case GNC_ENTRY_INTERP_VALUE:
case GNC_AMT_TYPE_VALUE:
help = _("Discount Type: Monetary Value");
break;
case GNC_ENTRY_INTERP_PERCENT:
case GNC_AMT_TYPE_PERCENT:
help = _("Discount Type: Percent");
break;
case GNC_ENTRY_INTERP_VALUE | GNC_ENTRY_PRETAX_FLAG:
help = _("Discount Type: Pre-Tax Monetary Value");
break;
case GNC_ENTRY_INTERP_PERCENT | GNC_ENTRY_PRETAX_FLAG:
help = _("Discount Type: Pre-Tax Percent");
break;
default:
help = _("Select the Discount Type");
break;
@ -473,6 +537,31 @@ static char * get_distype_help (VirtualLocation virt_loc, gpointer user_data)
return g_strdup (help);
}
static char * get_dishow_help (VirtualLocation virt_loc, gpointer user_data)
{
GncEntryLedger *ledger = user_data;
const char *help;
gint type;
type = gnc_entry_ledger_get_type (ledger, ENTRY_DISHOW_CELL);
switch (type) {
case GNC_DISC_PRETAX:
help = _("Tax computed after discount is applied");
break;
case GNC_DISC_SAMETIME:
help = _("Discount and tax both applied on pretax value");
break;
case GNC_DISC_POSTTAX:
help = _("Discount computed after tax is applied");
break;
default:
help = _("Select how to compute the Discount and Taxes");
break;
}
return g_strdup (help);
}
static char * get_pric_help (VirtualLocation virt_loc, gpointer user_data)
{
GncEntryLedger *ledger = user_data;
@ -497,52 +586,32 @@ static char * get_qty_help (VirtualLocation virt_loc, gpointer user_data)
return g_strdup (help);
}
static char * get_taxacc_help (VirtualLocation virt_loc, gpointer user_data)
static char * get_taxtable_help (VirtualLocation virt_loc, gpointer user_data)
{
GncEntryLedger *ledger = user_data;
const char *help;
help = gnc_table_get_entry (ledger->table, virt_loc);
if (!help || *help == '\0')
help = _("Enter the Account for tax holdings or choose one from the list");
help = _("Enter the Tax Table to apply to this entry");
return g_strdup (help);
}
static char * get_taxtype_help (VirtualLocation virt_loc, gpointer user_data)
static char * get_taxable_help (VirtualLocation virt_loc, gpointer user_data)
{
GncEntryLedger *ledger = user_data;
const char *help;
gint type;
type = gnc_entry_ledger_get_type (ledger, ENTRY_TAXTYPE_CELL);
help = _("Is this entry taxable?");
switch (type) {
case GNC_ENTRY_INTERP_VALUE:
help = _("Tax Type: Monetary Value");
break;
case GNC_ENTRY_INTERP_PERCENT:
help = _("Tax Type: Percent");
break;
default:
help = _("Select the Tax Type");
break;
}
return g_strdup (help);
}
static char * get_tax_help (VirtualLocation virt_loc, gpointer user_data)
static char * get_taxincluded_help (VirtualLocation virt_loc, gpointer user_data)
{
GncEntryLedger *ledger = user_data;
const char *help;
GncEntry *entry;
entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
if (GNC_ENTRY_INTERP_IS_VALUE (gncEntryGetDiscountType (entry)))
help = _("Enter the Tax Amount");
else
help = _("Enter the Tax Percent");
help = _("Is the tax already included in the price of this entry?");
return g_strdup (help);
}
@ -645,6 +714,31 @@ static CellIOFlags get_value_io_flags (VirtualLocation virt_loc,
return XACC_CELL_ALLOW_SHADOW;
}
static CellIOFlags get_tax_io_flags (VirtualLocation virt_loc,
gpointer user_data)
{
GncEntryLedger *ledger = user_data;
gboolean taxable;
taxable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
/* Only print the taxtable and taxincluded cells if taxable is true */
if (taxable)
return get_standard_io_flags (virt_loc, user_data);
/* Shadow the value, so the cell is loaded properly */
return XACC_CELL_ALLOW_SHADOW;
}
static CellIOFlags get_taxincluded_io_flags (VirtualLocation virt_loc,
gpointer user_data)
{
CellIOFlags flags = get_tax_io_flags (virt_loc, user_data);
if (flags == XACC_CELL_ALLOW_SHADOW)
return flags;
return flags | XACC_CELL_ALLOW_EXACT_ONLY;
}
/* GET BG_COLORS */
static guint32
@ -758,6 +852,16 @@ static void gnc_entry_ledger_save_cells (gpointer save_data,
gncEntrySetDiscountType (entry, type);
}
if (gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_DISHOW_CELL, TRUE)) {
gint type;
type = gnc_entry_ledger_get_type (ledger, ENTRY_DISHOW_CELL);
if (type != -1)
gncEntrySetDiscountHow (entry, type);
}
if (gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_PRIC_CELL, TRUE)) {
gnc_numeric amount;
@ -775,31 +879,30 @@ static void gnc_entry_ledger_save_cells (gpointer save_data,
}
if (gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_TAXACC_CELL, TRUE)) {
Account *acc;
ENTRY_TAXABLE_CELL, TRUE)) {
gboolean taxable;
acc = gnc_entry_ledger_get_account (ledger, ENTRY_TAXACC_CELL);
taxable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
gncEntrySetTaxable (entry, taxable);
}
if (acc != NULL)
gncEntrySetTaxAccount (entry, acc);
/* XXX: Only (re-set) these if taxable is TRUE? */
if (gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_TAXTABLE_CELL, TRUE)) {
GncTaxTable *table;
table = gnc_entry_ledger_get_taxtable (ledger, ENTRY_TAXTABLE_CELL);
if (table)
gncEntrySetTaxTable (entry, table);
}
if (gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_TAXTYPE_CELL, TRUE)) {
gint type;
ENTRY_TAXINCLUDED_CELL, TRUE)) {
gboolean taxincluded;
type = gnc_entry_ledger_get_type (ledger, ENTRY_TAXTYPE_CELL);
if (type != -1)
gncEntrySetTaxType (entry, type);
}
if (gnc_table_layout_get_cell_changed (ledger->table->layout,
ENTRY_TAX_CELL, TRUE)) {
gnc_numeric amount;
if (gnc_entry_ledger_get_numeric (ledger, ENTRY_TAX_CELL, &amount))
gncEntrySetTax (entry, amount);
taxincluded = gnc_entry_ledger_get_checkmark (ledger,
ENTRY_TAXINCLUDED_CELL);
gncEntrySetTaxIncluded (entry, taxincluded);
}
{
@ -839,16 +942,17 @@ static void gnc_entry_ledger_model_new_handlers (TableModel *model,
gpointer io_flags_handler;
} models[] = {
{ ENTRY_ACCT_CELL, get_acct_entry, get_acct_label, get_acct_help, get_standard_io_flags },
{ ENTRY_ACTN_CELL, get_actn_entry, get_actn_label, get_actn_help, get_standard_io_flags },
{ ENTRY_DATE_CELL, get_date_entry, get_date_label, get_date_help, get_standard_io_flags },
{ ENTRY_DESC_CELL, get_desc_entry, get_desc_label, get_desc_help, get_standard_io_flags },
{ ENTRY_DISC_CELL, get_disc_entry, get_disc_label, get_disc_help, get_standard_io_flags },
{ ENTRY_ACTN_CELL, get_actn_entry, get_actn_label, get_actn_help, get_standard_io_flags },
{ ENTRY_DATE_CELL, get_date_entry, get_date_label, get_date_help, get_standard_io_flags },
{ ENTRY_DESC_CELL, get_desc_entry, get_desc_label, get_desc_help, get_standard_io_flags },
{ ENTRY_DISC_CELL, get_disc_entry, get_disc_label, get_disc_help, get_standard_io_flags },
{ ENTRY_DISTYPE_CELL, get_distype_entry, get_distype_label, get_distype_help, get_typecell_io_flags },
{ ENTRY_PRIC_CELL, get_pric_entry, get_pric_label, get_pric_help, get_standard_io_flags },
{ ENTRY_QTY_CELL, get_qty_entry, get_qty_label, get_qty_help, get_standard_io_flags },
{ ENTRY_TAXACC_CELL, get_taxacc_entry, get_taxacc_label, get_taxacc_help, get_standard_io_flags },
{ ENTRY_TAXTYPE_CELL, get_taxtype_entry, get_taxtype_label, get_taxtype_help, get_typecell_io_flags },
{ ENTRY_TAX_CELL, get_tax_entry, get_tax_label, get_tax_help, get_standard_io_flags },
{ ENTRY_DISHOW_CELL, get_dishow_entry, get_dishow_label, get_dishow_help, get_typecell_io_flags },
{ ENTRY_PRIC_CELL, get_pric_entry, get_pric_label, get_pric_help, get_standard_io_flags },
{ ENTRY_QTY_CELL, get_qty_entry, get_qty_label, get_qty_help, get_standard_io_flags },
{ ENTRY_TAXABLE_CELL, get_taxable_entry, get_taxable_label, get_taxable_help, get_typecell_io_flags },
{ ENTRY_TAXTABLE_CELL, get_taxtable_entry, get_taxtable_label, get_taxtable_help, get_tax_io_flags },
{ ENTRY_TAXINCLUDED_CELL, get_taxincluded_entry, get_taxincluded_label, get_taxincluded_help, get_taxincluded_io_flags },
{ ENTRY_INV_CELL, get_inv_entry, get_inv_label, get_inv_help, get_inv_io_flags },
{ ENTRY_VALUE_CELL, get_value_entry, get_value_label, get_value_help, get_value_io_flags },
{ ENTRY_TAXVAL_CELL, get_taxval_entry, get_taxval_label, get_taxval_help, get_value_io_flags },

View File

@ -40,15 +40,20 @@ GncEntry * gnc_entry_ledger_get_entry (GncEntryLedger *ledger,
VirtualCellLocation vcell_loc);
Account * gnc_entry_ledger_get_account (GncEntryLedger *ledger,
const char * cell_name);
GncTaxTable * gnc_entry_ledger_get_taxtable (GncEntryLedger *ledger,
const char *cell_name);
gint gnc_entry_ledger_get_type (GncEntryLedger *ledger,
const char * cell_name);
gboolean gnc_entry_ledger_get_checkmark (GncEntryLedger *ledger,
const char * cell_name);
char gnc_entry_ledger_get_inv (GncEntryLedger *ledger, const char * cell_name);
gboolean gnc_entry_ledger_get_numeric (GncEntryLedger *ledger,
const char *cell_name,
gnc_numeric *value);
const char * gnc_entry_ledger_type_string_getter (char flag);
const char * gnc_entry_ledger_how_string_getter (char flag);
gboolean gnc_entry_ledger_find_entry (GncEntryLedger *ledger, GncEntry *entry,
VirtualCellLocation *vcell_loc);