gnucash maint: Bug 796766 - Credit note creating 'imbalance' with wrong entries
Geert Janssens
gjanssens at code.gnucash.org
Mon Aug 6 07:29:19 EDT 2018
Updated via https://github.com/Gnucash/gnucash/commit/d87fa3a5 (commit)
from https://github.com/Gnucash/gnucash/commit/69fef827 (commit)
commit d87fa3a5bed0b948f28651bf8b0897373cc7110e
Author: Geert Janssens <geert at kobaltwit.be>
Date: Mon Aug 6 13:29:12 2018 +0200
Bug 796766 - Credit note creating 'imbalance' with wrong entries
Add fix and regression test.
diff --git a/libgnucash/engine/gncInvoice.c b/libgnucash/engine/gncInvoice.c
index 616ef1b..60f643a 100644
--- a/libgnucash/engine/gncInvoice.c
+++ b/libgnucash/engine/gncInvoice.c
@@ -1509,8 +1509,11 @@ Transaction * gncInvoicePostToAccount (GncInvoice *invoice, Account *acc,
total = gncInvoiceGetTotal (invoice);
taxes = gncInvoiceGetTotalTaxList (invoice);
/* The two functions above return signs relative to the document
- * We need to convert them to balance values before we can use them here */
- if (is_cust_doc)
+ * We need to convert them to balance values before we can use them here
+ * Note the odd construct comparing two booleans is to xor them
+ * that is, only evaluate true if both are different.
+ */
+ if (is_cust_doc != is_cn)
{
GList *node;
total = gnc_numeric_neg (total);
diff --git a/libgnucash/engine/test/utest-Invoice.c b/libgnucash/engine/test/utest-Invoice.c
index fe8eb7b..e772652 100644
--- a/libgnucash/engine/test/utest-Invoice.c
+++ b/libgnucash/engine/test/utest-Invoice.c
@@ -31,66 +31,188 @@ void test_suite_gncInvoice ( void );
typedef struct
{
+ gboolean is_cn;
+ gboolean is_cust_doc;
+ gnc_numeric quantity;
+ gnc_numeric price;
+} InvoiceData;
+
+typedef struct
+{
QofBook *book;
Account *account;
+ Account *account2;
GncOwner owner;
GncCustomer *customer;
+ GncVendor *vendor;
gnc_commodity *commodity;
+
+ GncInvoice* invoice;
+ Transaction *trans;
} Fixture;
static void
setup( Fixture *fixture, gconstpointer pData )
{
+ const InvoiceData *data = (InvoiceData*) pData;
+
fixture->book = qof_book_new();
fixture->account = xaccMallocAccount(fixture->book);
+ fixture->account2 = xaccMallocAccount(fixture->book);
fixture->commodity = gnc_commodity_new(fixture->book, "foo", "bar", "xy", "xy", 100);
xaccAccountSetCommodity(fixture->account, fixture->commodity);
+ xaccAccountSetCommodity(fixture->account2, fixture->commodity);
- fixture->customer = gncCustomerCreate(fixture->book);
- gncOwnerInitCustomer(&fixture->owner, fixture->customer);
+ if (data->is_cust_doc)
+ {
+ fixture->customer = gncCustomerCreate(fixture->book);
+ gncOwnerInitCustomer(&fixture->owner, fixture->customer);
+ }
+ else
+ {
+ fixture->vendor = gncVendorCreate(fixture->book);
+ gncOwnerInitVendor(&fixture->owner, fixture->vendor);
+ }
+
+ fixture->invoice = gncInvoiceCreate(fixture->book);
}
static void
teardown( Fixture *fixture, gconstpointer pData )
{
- gncCustomerBeginEdit(fixture->customer);
- gncCustomerDestroy(fixture->customer);
+ const InvoiceData *data = (InvoiceData*) pData;
+
+ gncInvoiceBeginEdit(fixture->invoice);
+ gncInvoiceDestroy(fixture->invoice);
+
+ if (data->is_cust_doc)
+ {
+ gncCustomerBeginEdit(fixture->customer);
+ gncCustomerDestroy(fixture->customer);
+ }
+ else
+ {
+ gncVendorBeginEdit(fixture->vendor);
+ gncVendorDestroy(fixture->vendor);
+ }
xaccAccountBeginEdit(fixture->account);
xaccAccountDestroy(fixture->account);
+ xaccAccountBeginEdit(fixture->account2);
+ xaccAccountDestroy(fixture->account2);
gnc_commodity_destroy(fixture->commodity);
qof_book_destroy( fixture->book );
+};
+
+static void
+setup_with_invoice( Fixture *fixture, gconstpointer pData )
+{
+ const InvoiceData *data = (InvoiceData*) pData;
+
+ time64 ts1 = gnc_time(NULL);
+ time64 ts2 = ts1;
+ const char *desc = "Test description";
+ GncEntry *entry = NULL;
+
+ setup(fixture, pData);
+
+ fixture->invoice = gncInvoiceCreate(fixture->book);
+ gncInvoiceSetCurrency(fixture->invoice, fixture->commodity);
+ gncInvoiceSetOwner(fixture->invoice, &fixture->owner);
+
+ entry = gncEntryCreate(fixture->book);
+ gncEntrySetDate (entry, ts1);
+ gncEntrySetDateEntered (entry, ts1);
+ gncEntrySetDescription (entry, desc);
+ gncEntrySetDocQuantity (entry, data->quantity, data->is_cn);
+
+ if (data->is_cust_doc)
+ {
+ gncEntrySetInvAccount(entry, fixture->account);
+ gncInvoiceAddEntry (fixture->invoice, entry);
+ }
+ else
+ {
+ gncEntrySetBillAccount(entry, fixture->account);
+ gncBillAddEntry(fixture->invoice, entry);
+ }
+
+ fixture->trans = gncInvoicePostToAccount(fixture->invoice, fixture->account2, ts1, ts2, "memo", TRUE, FALSE);
+}
+
+static void
+teardown_with_invoice( Fixture *fixture, gconstpointer pData )
+{
+ gncInvoiceUnpost(fixture->invoice, TRUE);
+ gncInvoiceRemoveEntries (fixture->invoice);
+
+ teardown(fixture, pData);
}
static void
test_invoice_post ( Fixture *fixture, gconstpointer pData )
{
- GncInvoice *invoice = gncInvoiceCreate(fixture->book);
time64 ts1 = gnc_time(NULL);
time64 ts2 = ts1;
- g_assert(invoice);
- g_assert(!gncInvoiceGetIsCreditNote(invoice));
- g_assert(gncInvoiceGetActive(invoice));
- g_assert(gncInvoiceGetPostedAcc(invoice) == NULL);
+ g_assert(fixture->invoice);
+ g_assert(!gncInvoiceGetIsCreditNote(fixture->invoice));
+ g_assert(gncInvoiceGetActive(fixture->invoice));
+ g_assert(gncInvoiceGetPostedAcc(fixture->invoice) == NULL);
- gncInvoiceSetCurrency(invoice, fixture->commodity);
+ gncInvoiceSetCurrency(fixture->invoice, fixture->commodity);
- gncInvoiceSetOwner(invoice, &fixture->owner);
+ gncInvoiceSetOwner(fixture->invoice, &fixture->owner);
g_test_message( "Will now post the invoice" );
- g_assert(!gncInvoiceIsPosted(invoice));
- gncInvoicePostToAccount(invoice, fixture->account, ts1, ts2, "memo", TRUE, FALSE);
- g_assert(gncInvoiceIsPosted(invoice));
+ g_assert(!gncInvoiceIsPosted(fixture->invoice));
+ gncInvoicePostToAccount(fixture->invoice, fixture->account, ts1, ts2, "memo", TRUE, FALSE);
+ g_assert(gncInvoiceIsPosted(fixture->invoice));
+
+ gncInvoiceUnpost(fixture->invoice, TRUE);
+ g_assert(!gncInvoiceIsPosted(fixture->invoice));
+}
+
+static void
+test_invoice_posted_trans ( Fixture *fixture, gconstpointer pData )
+{
+ const InvoiceData *data = (InvoiceData*) pData;
- gncInvoiceUnpost(invoice, TRUE);
- g_assert(!gncInvoiceIsPosted(invoice));
+ gnc_numeric total = gncInvoiceGetTotal(fixture->invoice);
+ gnc_numeric acct_balance, acct2_balance;
+
+ g_assert (1 == xaccAccountCountSplits (fixture->account, FALSE));
+ g_assert (1 == xaccAccountCountSplits (fixture->account2, FALSE));
+
+ acct_balance = xaccAccountGetBalance(fixture->account);
+ acct2_balance = xaccAccountGetBalance(fixture->account2);
+
+ // Handle sign reversals (document values vs balance values)
+ if (data->is_cn != !data->is_cust_doc)
+ {
+ g_assert (gnc_numeric_equal (gnc_numeric_neg(acct_balance), total));
+ g_assert (gnc_numeric_equal (acct2_balance, total));
+ }
+ else
+ {
+ g_assert (gnc_numeric_equal (acct_balance, total));
+ g_assert (gnc_numeric_equal (gnc_numeric_neg(acct2_balance), total));
+ }
}
void
test_suite_gncInvoice ( void )
{
- GNC_TEST_ADD( suitename, "post", Fixture, NULL, setup, test_invoice_post, teardown );
+ InvoiceData pData = { FALSE, FALSE, { 1000, 100 }, { 2000, 100 } }; // Vendor bill
+ GNC_TEST_ADD( suitename, "post/unpost", Fixture, &pData, setup, test_invoice_post, teardown );
+
+ GNC_TEST_ADD( suitename, "post trans - vendor bill", Fixture, &pData, setup_with_invoice, test_invoice_posted_trans, teardown_with_invoice );
+ pData.is_cn = TRUE; // Vendor credit note
+ GNC_TEST_ADD( suitename, "post trans - vendor credit note", Fixture, &pData, setup_with_invoice, test_invoice_posted_trans, teardown_with_invoice );
+ pData.is_cust_doc = TRUE; // Customer credit note
+ GNC_TEST_ADD( suitename, "post trans - customer creditnote", Fixture, &pData, setup_with_invoice, test_invoice_posted_trans, teardown_with_invoice );
+ pData.is_cn = FALSE; // Customer invoice
+ GNC_TEST_ADD( suitename, "post trans - customer invoice", Fixture, &pData, setup_with_invoice, test_invoice_posted_trans, teardown_with_invoice );
}
Summary of changes:
libgnucash/engine/gncInvoice.c | 7 +-
libgnucash/engine/test/utest-Invoice.c | 156 +++++++++++++++++++++++++++++----
2 files changed, 144 insertions(+), 19 deletions(-)
More information about the gnucash-changes
mailing list