mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Add tax_type and discount_type to GncEntry -- this allows you
to change how the Tax and Discount fields are handled (values or percentages) Add code to link a GncInvoice to a Transaction, and to lookup the GncInvoice from a linked Transaction. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@5989 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
@@ -28,7 +28,9 @@ struct _gncEntry {
|
||||
gnc_numeric quantity;
|
||||
gnc_numeric price;
|
||||
gnc_numeric tax;
|
||||
gint tax_type;
|
||||
gnc_numeric discount;
|
||||
gint disc_type;
|
||||
Account * account;
|
||||
Account * taxaccount;
|
||||
|
||||
@@ -183,6 +185,24 @@ void gncEntrySetInvoice (GncEntry *entry, GncInvoice *invoice)
|
||||
entry->dirty = TRUE;
|
||||
}
|
||||
|
||||
void gncEntrySetTaxType (GncEntry *entry, gint type)
|
||||
{
|
||||
if (!entry) return;
|
||||
if (type < 0 || type > 3) return;
|
||||
|
||||
entry->tax_type = type;
|
||||
entry->dirty = TRUE;
|
||||
}
|
||||
|
||||
void gncEntrySetDiscountType (GncEntry *entry, gint type)
|
||||
{
|
||||
if (!entry) return;
|
||||
if (type < 0 || type > 3) return;
|
||||
|
||||
entry->disc_type = type;
|
||||
entry->dirty = TRUE;
|
||||
}
|
||||
|
||||
void gncEntrySetDirty (GncEntry *entry, gboolean dirty)
|
||||
{
|
||||
if (!entry) return;
|
||||
@@ -270,6 +290,18 @@ GncOrder * gncEntryGetOrder (GncEntry *entry)
|
||||
return entry->order;
|
||||
}
|
||||
|
||||
gint gncEntryGetTaxType (GncEntry *entry)
|
||||
{
|
||||
if (!entry) return 0;
|
||||
return entry->tax_type;
|
||||
}
|
||||
|
||||
gint gncEntryGetDiscountType (GncEntry *entry)
|
||||
{
|
||||
if (!entry) return 0;
|
||||
return entry->disc_type;
|
||||
}
|
||||
|
||||
void gncEntryCommitEdit (GncEntry *entry)
|
||||
{
|
||||
if (!entry) return;
|
||||
|
||||
@@ -16,6 +16,17 @@ typedef struct _gncEntry GncEntry;
|
||||
|
||||
#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_INTERP_PRETAX 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)
|
||||
|
||||
/* Create/Destroy Functions */
|
||||
|
||||
GncEntry *gncEntryCreate (GncBusiness *business);
|
||||
@@ -29,7 +40,9 @@ 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 gncEntrySetAccount (GncEntry *entry, Account *acc);
|
||||
void gncEntrySetTaxAccount (GncEntry *entry, Account *acc);
|
||||
@@ -44,7 +57,10 @@ const char * gncEntryGetAction (GncEntry *entry);
|
||||
gnc_numeric gncEntryGetQuantity (GncEntry *entry);
|
||||
gnc_numeric gncEntryGetPrice (GncEntry *entry);
|
||||
gnc_numeric gncEntryGetTax (GncEntry *entry);
|
||||
gint gncEntryGetTaxType (GncEntry *entry);
|
||||
gnc_numeric gncEntryGetDiscount (GncEntry *entry);
|
||||
gint gncEntryGetDiscountType (GncEntry *entry);
|
||||
|
||||
|
||||
Account * gncEntryGetAccount (GncEntry *entry);
|
||||
Account * gncEntryGetTaxAccount (GncEntry *entry);
|
||||
|
||||
@@ -48,6 +48,9 @@ struct _gncInvoice {
|
||||
gboolean dirty;
|
||||
};
|
||||
|
||||
#define GNC_INVOICE_ID "gncInvoice"
|
||||
#define GNC_INVOICE_GUID "invoice-guid"
|
||||
|
||||
#define CACHE_INSERT(str) g_cache_insert(gnc_engine_get_string_cache(), (gpointer)(str));
|
||||
#define CACHE_REMOVE(str) g_cache_remove(gnc_engine_get_string_cache(), (str));
|
||||
|
||||
@@ -180,6 +183,22 @@ void gncInvoiceSetDirty (GncInvoice *invoice, gboolean dirty)
|
||||
invoice->dirty = dirty;
|
||||
}
|
||||
|
||||
void gncInvoiceSetPostedTxn (GncInvoice *invoice, Transaction *txn)
|
||||
{
|
||||
if (!invoice) return;
|
||||
|
||||
invoice->posted_txn = txn;
|
||||
invoice->dirty = TRUE;
|
||||
}
|
||||
|
||||
void gncInvoiceSetPostedAcc (GncInvoice *invoice, Account *acc)
|
||||
{
|
||||
if (!invoice) return;
|
||||
|
||||
invoice->posted_acc = acc;
|
||||
invoice->dirty = TRUE;
|
||||
}
|
||||
|
||||
void gncInvoiceAddEntry (GncInvoice *invoice, GncEntry *entry)
|
||||
{
|
||||
GncInvoice *old;
|
||||
@@ -277,6 +296,18 @@ const char * gncInvoiceGetNotes (GncInvoice *invoice)
|
||||
return invoice->notes;
|
||||
}
|
||||
|
||||
Transaction * gncInvoiceGetPostedTxn (GncInvoice *invoice)
|
||||
{
|
||||
if (!invoice) return NULL;
|
||||
return invoice->posted_txn;
|
||||
}
|
||||
|
||||
Account * gncInvoiceGetPostedAcc (GncInvoice *invoice)
|
||||
{
|
||||
if (!invoice) return NULL;
|
||||
return invoice->posted_acc;
|
||||
}
|
||||
|
||||
gboolean gncInvoiceGetActive (GncInvoice *invoice)
|
||||
{
|
||||
if (!invoice) return FALSE;
|
||||
@@ -295,6 +326,186 @@ gboolean gncInvoiceIsDirty (GncInvoice *invoice)
|
||||
return invoice->dirty;
|
||||
}
|
||||
|
||||
void gncInvoiceAttachInvoiceToTxn (GncInvoice *invoice, Transaction *txn)
|
||||
{
|
||||
kvp_frame *kvp;
|
||||
kvp_value *value;
|
||||
|
||||
if (!invoice || !txn)
|
||||
return;
|
||||
|
||||
if (invoice->posted_txn) return; /* Cannot reset invoice's txn */
|
||||
|
||||
xaccTransBeginEdit (txn);
|
||||
kvp = xaccTransGetSlots (txn);
|
||||
value = kvp_value_new_guid (gncInvoiceGetGUID (invoice));
|
||||
kvp_frame_set_slot_path (kvp, value, GNC_INVOICE_ID, GNC_INVOICE_GUID, NULL);
|
||||
kvp_value_delete (value);
|
||||
xaccTransCommitEdit (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 *date)
|
||||
{
|
||||
Transaction *txn;
|
||||
GList *item, *iter;
|
||||
GList *splitinfo = NULL;
|
||||
GNCSession *session;
|
||||
gnc_numeric total;
|
||||
gnc_commodity *commonCommodity = NULL;
|
||||
struct acct_val {
|
||||
Account * acc;
|
||||
gnc_numeric val;
|
||||
} *acc_val;
|
||||
|
||||
if (!invoice || !acc) return NULL;
|
||||
|
||||
/* XXX: Need to obtain the session */
|
||||
txn = xaccMallocTransaction (session);
|
||||
xaccTransBeginEdit (txn);
|
||||
|
||||
/* Figure out the common currency */
|
||||
/* XXX */
|
||||
|
||||
/* Set Transaction Description (customer), Num (invoice ID), Currency */
|
||||
xaccTransSetDescription
|
||||
(txn,
|
||||
((gncInvoiceGetType (invoice) == GNC_INVOICE_CUSTOMER) ?
|
||||
gncCustomerGetName (gncInvoiceGetCustomer (invoice)) :
|
||||
gncVendorGetName (gncInvoiceGetVendor (invoice))));
|
||||
|
||||
xaccTransSetNum (txn, gncInvoiceGetID (invoice));
|
||||
xaccTransSetCurrency (txn, commonCommodity);
|
||||
|
||||
/* Entered and Posted at date */
|
||||
if (date) {
|
||||
xaccTransSetDateEnteredTS (txn, date);
|
||||
xaccTransSetDatePostedTS (txn, 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) {
|
||||
GncEntry * entry = iter->data;
|
||||
Account *this_acc = gncEntryGetAccount (entry);
|
||||
gnc_numeric disc = gncEntryGetDiscount (entry);
|
||||
gnc_numeric subtotal = gnc_numeric_mul (gncEntryGetQuantity (entry),
|
||||
gncEntryGetPrice (entry),
|
||||
100, /* XXX */
|
||||
GNC_RND_ROUND);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Now compute the split value and add it to the totals */
|
||||
{
|
||||
gint disc_type = gncEntryGetDiscountType (entry);
|
||||
gnc_numeric value;
|
||||
|
||||
if (GNC_ENTRY_INTERP_IS_PERCENT (disc_type))
|
||||
disc = gnc_numeric_mul (subtotal, disc, 100 /* XXX */, GNC_RND_ROUND);
|
||||
|
||||
value = gnc_numeric_sub_fixed (subtotal, disc);
|
||||
if (disc_type & GNC_ENTRY_INTERP_PRETAX)
|
||||
subtotal = value;
|
||||
|
||||
acc_val->val = gnc_numeric_add_fixed (acc_val->val, value);
|
||||
total = gnc_numeric_add_fixed (total, value);
|
||||
}
|
||||
|
||||
/* Repeat for the Entry Tax */
|
||||
this_acc = gncEntryGetTaxAccount (entry);
|
||||
if (this_acc) {
|
||||
gnc_numeric tax = gncEntryGetTax (entry);
|
||||
gint tax_type = gncEntryGetTaxType (entry);
|
||||
|
||||
GET_OR_ADD_ACCVAL (splitinfo, this_acc, acc_val);
|
||||
|
||||
if (GNC_ENTRY_INTERP_IS_PERCENT (tax_type))
|
||||
tax = gnc_numeric_mul (subtotal, tax, 100 /* XXX */, GNC_RND_ROUND);
|
||||
|
||||
acc_val->val = gnc_numeric_add_fixed (acc_val->val, tax);
|
||||
total = gnc_numeric_add_fixed (total, tax);
|
||||
}
|
||||
} /* for */
|
||||
|
||||
/* Iterate through the splitinfo list and generate the splits */
|
||||
for (iter = splitinfo; iter; iter = iter->next) {
|
||||
Split *split;
|
||||
acc_val = iter->data;
|
||||
|
||||
split = xaccMallocSplit (session);
|
||||
/* set action and memo? */
|
||||
|
||||
xaccSplitSetBaseValue (split, acc_val->val, commonCommodity);
|
||||
xaccAccountBeginEdit (acc_val->acc);
|
||||
xaccAccountInsertSplit (acc_val->acc, split);
|
||||
xaccAccountCommitEdit (acc_val->acc);
|
||||
xaccTransAppendSplit (txn, split);
|
||||
}
|
||||
|
||||
/* Now create the Posted split (which is negative -- it's a credit) */
|
||||
{
|
||||
Split *split = xaccMallocSplit (session);
|
||||
/* Set action/memo */
|
||||
xaccSplitSetBaseValue (split, gnc_numeric_neg (total), commonCommodity);
|
||||
xaccAccountBeginEdit (acc);
|
||||
xaccAccountInsertSplit (acc, split);
|
||||
xaccAccountCommitEdit (acc);
|
||||
xaccTransAppendSplit (txn, split);
|
||||
}
|
||||
|
||||
gncInvoiceSetPostedAcc (invoice, acc);
|
||||
gncInvoiceSetPostedTxn (invoice, txn);
|
||||
|
||||
xaccTransCommitEdit (txn);
|
||||
|
||||
return txn;
|
||||
}
|
||||
|
||||
GncInvoice * gncInvoiceGetInvoiceFromTxn (Transaction *txn)
|
||||
{
|
||||
kvp_frame *kvp;
|
||||
kvp_value *value;
|
||||
GUID *guid;
|
||||
GncBusiness *business;
|
||||
|
||||
if (!txn) return NULL;
|
||||
|
||||
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);
|
||||
/* XXX: Need to get GNCSession from Transaction */
|
||||
/* XXX: lookup invoice from session/guid */
|
||||
|
||||
return gncBusinessLookupGUID (business, GNC_INVOICE_MODULE_NAME, guid);
|
||||
}
|
||||
|
||||
void gncInvoiceBeginEdit (GncInvoice *invoice)
|
||||
{
|
||||
if (!invoice) return;
|
||||
|
||||
@@ -55,8 +55,21 @@ gint gncInvoiceGetTerms (GncInvoice *invoice);
|
||||
const char * gncInvoiceGetNotes (GncInvoice *invoice);
|
||||
gboolean gncInvoiceGetActive (GncInvoice *invoice);
|
||||
|
||||
Transaction * gncInvoiceGetPostedTxn (GncInvoice *invoice);
|
||||
Account * gncInvoiceGetPostedAcc (GncInvoice *invoice);
|
||||
|
||||
GList * gncInvoiceGetEntries (GncInvoice *invoice);
|
||||
|
||||
/* Post this invoice to an account. Returns the new Transaction
|
||||
* that is tied to this invoice. The transaction is set with
|
||||
* the posted date.
|
||||
*/
|
||||
Transaction * gncInvoicePostToAccount (GncInvoice *invoice, Account *acc,
|
||||
Timespec *date);
|
||||
|
||||
/* Given a transaction, find and return the Invoice */
|
||||
GncInvoice * gncInvoiceGetInvoiceFromTxn (Transaction *txn);
|
||||
|
||||
gboolean gncInvoiceIsDirty (GncInvoice *invoice);
|
||||
void gncInvoiceCommitEdit (GncInvoice *invoice);
|
||||
|
||||
|
||||
@@ -18,5 +18,6 @@ void gncInvoiceSetGUID (GncInvoice *invoice, const GUID *guid);
|
||||
void gncInvoiceSetDirty (GncInvoice *invoice, gboolean dirty);
|
||||
void gncInvoiceSetPostedAcc (GncInvoice *invoice, Account *acc);
|
||||
void gncInvoiceSetPostedTxn (GncInvoice *invoice, Transaction *txn);
|
||||
void gncInvoiceAttachInvoiceToTxn (GncInvoice *invoice, Transaction *txn);
|
||||
|
||||
#endif /* GNC_INVOICEP_H_ */
|
||||
|
||||
Reference in New Issue
Block a user