[Gnucash-changes] r13363 - gnucash/trunk/src/engine - Separate the
Split functions from Transaction.c into Split.c.
Chris Shoemaker
chris at cvs.gnucash.org
Wed Feb 22 16:52:47 EST 2006
Author: chris
Date: 2006-02-22 16:52:46 -0500 (Wed, 22 Feb 2006)
New Revision: 13363
Trac: http://svn.gnucash.org/trac/changeset/13363
Added:
gnucash/trunk/src/engine/Split.c
gnucash/trunk/src/engine/Split.h
gnucash/trunk/src/engine/SplitP.h
Modified:
gnucash/trunk/src/engine/Makefile.am
gnucash/trunk/src/engine/Transaction.c
gnucash/trunk/src/engine/Transaction.h
gnucash/trunk/src/engine/TransactionP.h
Log:
Separate the Split functions from Transaction.c into Split.c.
Introduce xaccSplitVoid() and xaccSplitUnvoid() to aid the separation.
Modified: gnucash/trunk/src/engine/Makefile.am
===================================================================
--- gnucash/trunk/src/engine/Makefile.am 2006-02-22 17:41:58 UTC (rev 13362)
+++ gnucash/trunk/src/engine/Makefile.am 2006-02-22 21:52:46 UTC (rev 13363)
@@ -25,6 +25,7 @@
Scrub.c \
Scrub2.c \
Scrub3.c \
+ Split.c \
TransLog.c \
Transaction.c \
cap-gains.c \
@@ -62,6 +63,7 @@
Scrub.h \
Scrub2.h \
Scrub3.h \
+ Split.h \
TransLog.h \
Transaction.h \
cap-gains.h \
@@ -89,6 +91,7 @@
QueryP.h \
SchedXactionP.h \
ScrubP.h \
+ SplitP.h \
SX-book.h \
SX-ttinfo.h \
TransactionP.h \
Copied: gnucash/trunk/src/engine/Split.c (from rev 13362, gnucash/trunk/src/engine/Transaction.c)
===================================================================
--- gnucash/trunk/src/engine/Transaction.c 2006-02-22 17:41:58 UTC (rev 13362)
+++ gnucash/trunk/src/engine/Split.c 2006-02-22 21:52:46 UTC (rev 13363)
@@ -0,0 +1,1687 @@
+/********************************************************************\
+ * Split.c -- split implementation *
+ * Copyright (C) 1997 Robin D. Clark *
+ * Copyright (C) 1997-2003 Linas Vepstas <linas at linas.org> *
+ * Copyright (C) 2000 Bill Gribble <grib at billgribble.com> *
+ * Copyright (c) 2006 David Hampton <hampton at employees.org> *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "Split.h"
+#include "AccountP.h"
+#include "Group.h"
+#include "Scrub.h"
+#include "Scrub3.h"
+#include "TransactionP.h"
+#include "TransLog.h"
+#include "cap-gains.h"
+#include "gnc-commodity.h"
+#include "gnc-engine.h"
+#include "gnc-lot-p.h"
+#include "gnc-lot.h"
+
+const char *void_former_amt_str = "void-former-amount";
+const char *void_former_val_str = "void-former-value";
+
+#define PRICE_SIGFIGS 6
+
+/* This static indicates the debugging module that this .o belongs to. */
+static QofLogModule log_module = GNC_MOD_ENGINE;
+
+/********************************************************************\
+ * xaccInitSplit
+ * Initialize a Split structure
+\********************************************************************/
+
+static void
+xaccInitSplit(Split * split, QofBook *book)
+{
+ /* fill in some sane defaults */
+ split->acc = NULL;
+ split->parent = NULL;
+ split->lot = NULL;
+
+ split->action = gnc_string_cache_insert("");
+ split->memo = gnc_string_cache_insert("");
+ split->reconciled = NREC;
+ split->amount = gnc_numeric_zero();
+ split->value = gnc_numeric_zero();
+
+ split->date_reconciled.tv_sec = 0;
+ split->date_reconciled.tv_nsec = 0;
+
+ split->balance = gnc_numeric_zero();
+ split->cleared_balance = gnc_numeric_zero();
+ split->reconciled_balance = gnc_numeric_zero();
+
+ split->idata = 0;
+
+ split->gains = GAINS_STATUS_UNKNOWN;
+ split->gains_split = NULL;
+
+ qof_instance_init(&split->inst, GNC_ID_SPLIT, book);
+}
+
+void
+xaccSplitReinit(Split * split)
+{
+ /* fill in some sane defaults */
+ split->acc = NULL;
+ split->parent = NULL;
+ split->lot = NULL;
+
+ CACHE_REPLACE(split->action, "");
+ CACHE_REPLACE(split->memo, "");
+ split->reconciled = NREC;
+ split->amount = gnc_numeric_zero();
+ split->value = gnc_numeric_zero();
+
+ split->date_reconciled.tv_sec = 0;
+ split->date_reconciled.tv_nsec = 0;
+
+ split->balance = gnc_numeric_zero();
+ split->cleared_balance = gnc_numeric_zero();
+ split->reconciled_balance = gnc_numeric_zero();
+
+ if (split->inst.kvp_data)
+ kvp_frame_delete(split->inst.kvp_data);
+ split->inst.kvp_data = kvp_frame_new();
+ split->idata = 0;
+
+ split->gains = GAINS_STATUS_UNKNOWN;
+ split->gains_split = NULL;
+}
+
+/********************************************************************\
+\********************************************************************/
+
+Split *
+xaccMallocSplit(QofBook *book)
+{
+ Split *split;
+ g_return_val_if_fail (book, NULL);
+
+ split = g_new0 (Split, 1);
+ xaccInitSplit (split, book);
+
+ return split;
+}
+
+/********************************************************************\
+\********************************************************************/
+/* This routine is not exposed externally, since it does weird things,
+ * like not really setting up the parent account correctly, and ditto
+ * the parent transaction. This routine is prone to programmer error
+ * if not used correctly. It is used only by the edit-rollback code.
+ * Don't get duped!
+ */
+
+Split *
+xaccDupeSplit (const Split *s)
+{
+ Split *split = g_new0 (Split, 1);
+
+ /* Trash the guid and entity table. We don't want to mistake
+ * the cloned splits as something official. If we ever use this
+ * split, we'll have to fix this up.
+ */
+ split->inst.entity.e_type = NULL;
+ split->inst.entity.guid = *guid_null();
+ split->inst.entity.collection = NULL;
+ split->inst.book = s->inst.book;
+
+ split->parent = s->parent;
+ split->acc = s->acc;
+ split->lot = s->lot;
+
+ split->memo = gnc_string_cache_insert(s->memo);
+ split->action = gnc_string_cache_insert(s->action);
+
+ split->inst.kvp_data = kvp_frame_copy (s->inst.kvp_data);
+
+ split->reconciled = s->reconciled;
+ split->date_reconciled = s->date_reconciled;
+
+ split->value = s->value;
+ split->amount = s->amount;
+
+ /* no need to futz with the balances; these get wiped each time ...
+ * split->balance = s->balance;
+ * split->cleared_balance = s->cleared_balance;
+ * split->reconciled_balance = s->reconciled_balance;
+ */
+
+ return split;
+}
+
+Split *
+xaccSplitClone (const Split *s)
+{
+ Split *split = g_new0 (Split, 1);
+
+ split->parent = NULL;
+ split->memo = gnc_string_cache_insert(s->memo);
+ split->action = gnc_string_cache_insert(s->action);
+ split->reconciled = s->reconciled;
+ split->date_reconciled = s->date_reconciled;
+ split->value = s->value;
+ split->amount = s->amount;
+ split->balance = s->balance;
+ split->cleared_balance = s->cleared_balance;
+ split->reconciled_balance = s->reconciled_balance;
+ split->idata = 0;
+
+ split->gains = GAINS_STATUS_UNKNOWN;
+ split->gains_split = NULL;
+
+ qof_instance_init(&split->inst, GNC_ID_SPLIT, s->inst.book);
+ kvp_frame_delete(split->inst.kvp_data);
+ split->inst.kvp_data = kvp_frame_copy(s->inst.kvp_data);
+
+ xaccAccountInsertSplit(s->acc, split);
+ if (s->lot)
+ {
+ /* FIXME: Doesn't look right. */
+ s->lot->splits = g_list_append (s->lot->splits, split);
+ s->lot->is_closed = -1;
+ }
+ return split;
+}
+
+#ifdef DUMP_FUNCTIONS
+static void
+xaccSplitDump (const Split *split, const char *tag)
+{
+ printf(" %s Split %p", tag, split);
+ printf(" GUID: %s\n", guid_to_string(&split->guid));
+ printf(" Book: %p\n", split->inst.book);
+ printf(" Account: %p\n", split->acc);
+ printf(" Lot: %p\n", split->lot);
+ printf(" Parent: %p\n", split->parent);
+ printf(" Memo: %s\n", split->memo ? split->memo : "(null)");
+ printf(" Action: %s\n", split->action ? split->action : "(null)");
+ printf(" KVP Data: %p\n", split->inst.kvp_data);
+ printf(" Recncld: %c (date %s)\n", split->reconciled,
+ gnc_print_date(split->date_reconciled));
+ printf(" Value: %s\n", gnc_numeric_to_string(split->value));
+ printf(" Amount: %s\n", gnc_numeric_to_string(split->amount));
+ printf(" Balance: %s\n", gnc_numeric_to_string(split->balance));
+ printf(" CBalance: %s\n", gnc_numeric_to_string(split->cleared_balance));
+ printf(" RBalance: %s\n",
+ gnc_numeric_to_string(split->reconciled_balance));
+ printf(" idata: %x\n", split->idata);
+}
+#endif
+
+/********************************************************************\
+\********************************************************************/
+
+void
+xaccFreeSplit (Split *split)
+{
+ if (!split) return;
+
+ /* Debug double-free's */
+ if (((char *) 1) == split->memo)
+ {
+ PERR ("double-free %p", split);
+ return;
+ }
+ gnc_string_cache_remove(split->memo);
+ gnc_string_cache_remove(split->action);
+
+ /* Just in case someone looks up freed memory ... */
+ split->memo = (char *) 1;
+ split->action = NULL;
+ split->reconciled = NREC;
+ split->amount = gnc_numeric_zero();
+ split->value = gnc_numeric_zero();
+ split->parent = NULL;
+ split->lot = NULL;
+ split->acc = NULL;
+
+ split->date_reconciled.tv_sec = 0;
+ split->date_reconciled.tv_nsec = 0;
+
+ // Is this right?
+ if (split->gains_split) split->gains_split->gains_split = NULL;
+ qof_instance_release(&split->inst);
+ g_free(split);
+}
+
+/*
+ * Helper routine for xaccSplitEqual.
+ */
+static gboolean
+xaccSplitEqualCheckBal (const char *tag, gnc_numeric a, gnc_numeric b)
+{
+ char *str_a, *str_b;
+
+ if (gnc_numeric_equal (a, b))
+ return TRUE;
+
+ str_a = gnc_numeric_to_string (a);
+ str_b = gnc_numeric_to_string (b);
+
+ PWARN ("%sbalances differ: %s vs %s", tag, str_a, str_b);
+
+ g_free (str_a);
+ g_free (str_b);
+
+ return FALSE;
+}
+
+/********************************************************************
+ * xaccSplitEqual
+ ********************************************************************/
+gboolean
+xaccSplitEqual(const Split *sa, const Split *sb,
+ gboolean check_guids,
+ gboolean check_balances,
+ gboolean check_txn_splits)
+{
+ if (!sa && !sb) return TRUE; /* Arguable. FALSE is better, methinks */
+
+ if (!sa || !sb)
+ {
+ PWARN ("one is NULL");
+ return FALSE;
+ }
+
+ if (sa == sb) return TRUE;
+
+ if (check_guids) {
+ if (!guid_equal(&(sa->inst.entity.guid), &(sb->inst.entity.guid)))
+ {
+ PWARN ("GUIDs differ");
+ return FALSE;
+ }
+ }
+
+ /* Since these strings are cached we can just use pointer equality */
+ if (sa->memo != sb->memo)
+ {
+ PWARN ("memos differ: (%p)%s vs (%p)%s",
+ sa->memo, sa->memo, sb->memo, sb->memo);
+ return FALSE;
+ }
+
+ if (sa->action != sb->action)
+ {
+ PWARN ("actions differ: %s vs %s", sa->action, sb->action);
+ return FALSE;
+ }
+
+ if (kvp_frame_compare(sa->inst.kvp_data, sb->inst.kvp_data) != 0)
+ {
+ char *frame_a;
+ char *frame_b;
+
+ frame_a = kvp_frame_to_string (sa->inst.kvp_data);
+ frame_b = kvp_frame_to_string (sb->inst.kvp_data);
+
+ PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
+
+ g_free (frame_a);
+ g_free (frame_b);
+
+ return FALSE;
+ }
+
+ if (sa->reconciled != sb->reconciled)
+ {
+ PWARN ("reconcile flags differ: %c vs %c", sa->reconciled, sb->reconciled);
+ return FALSE;
+ }
+
+ if (timespec_cmp(&(sa->date_reconciled), &(sb->date_reconciled)))
+ {
+ PWARN ("reconciled date differs");
+ return FALSE;
+ }
+
+ if (!gnc_numeric_eq(xaccSplitGetAmount (sa), xaccSplitGetAmount (sb)))
+ {
+ char *str_a;
+ char *str_b;
+
+ str_a = gnc_numeric_to_string (xaccSplitGetAmount (sa));
+ str_b = gnc_numeric_to_string (xaccSplitGetAmount (sb));
+
+ PWARN ("amounts differ: %s vs %s", str_a, str_b);
+
+ g_free (str_a);
+ g_free (str_b);
+
+ return FALSE;
+ }
+
+ if (!gnc_numeric_eq(xaccSplitGetValue (sa), xaccSplitGetValue (sb)))
+ {
+ char *str_a;
+ char *str_b;
+
+ str_a = gnc_numeric_to_string (xaccSplitGetValue (sa));
+ str_b = gnc_numeric_to_string (xaccSplitGetValue (sb));
+
+ PWARN ("values differ: %s vs %s", str_a, str_b);
+
+ g_free (str_a);
+ g_free (str_b);
+
+ return FALSE;
+ }
+
+ if (check_balances) {
+ if (!xaccSplitEqualCheckBal ("", sa->balance, sb->balance))
+ return FALSE;
+ if (!xaccSplitEqualCheckBal ("cleared ", sa->cleared_balance,
+ sb->cleared_balance))
+ return FALSE;
+ if (!xaccSplitEqualCheckBal ("reconciled ", sa->reconciled_balance,
+ sb->reconciled_balance))
+ return FALSE;
+ }
+
+ if (!xaccTransEqual(sa->parent, sb->parent, check_guids, check_txn_splits,
+ check_balances, FALSE))
+ {
+ PWARN ("transactions differ");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+add_keys_to_list(gpointer key, gpointer val, gpointer list)
+{
+ *(GList **)list = g_list_prepend(*(GList **)list, key);
+}
+
+GList *
+xaccSplitListGetUniqueTransactions(const GList *splits)
+{
+ const GList *node;
+ GList *transList = NULL;
+ GHashTable *transHash = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+ for(node = splits; node; node = node->next) {
+ Transaction *trans = xaccSplitGetParent((Split *)(node->data));
+ g_hash_table_insert(transHash, trans, trans);
+ }
+ g_hash_table_foreach(transHash, add_keys_to_list, &transList);
+ g_hash_table_destroy(transHash);
+ return transList;
+}
+
+/********************************************************************
+ * Account funcs
+ ********************************************************************/
+
+Account *
+xaccSplitGetAccount (const Split *s)
+{
+ return s ? s->acc : NULL;
+}
+
+/********************************************************************\
+\********************************************************************/
+
+Split *
+xaccSplitLookup (const GUID *guid, QofBook *book)
+{
+ QofCollection *col;
+ if (!guid || !book) return NULL;
+ col = qof_book_get_collection (book, GNC_ID_SPLIT);
+ return (Split *) qof_collection_lookup_entity (col, guid);
+}
+
+/********************************************************************\
+\********************************************************************/
+/* Routines for marking splits dirty, and for sending out change
+ * events. Note that we can't just mark-n-generate-event in one
+ * step, since sometimes we need to mark things up before its suitable
+ * to send out a change event.
+ */
+
+/* CHECKME: This function modifies the Split without dirtying or
+ checking its parent. Is that correct? */
+void
+xaccSplitDetermineGainStatus (Split *split)
+{
+ Split *other;
+ KvpValue *val;
+
+ if (GAINS_STATUS_UNKNOWN != split->gains) return;
+
+ other = xaccSplitGetCapGainsSplit (split);
+ if (other)
+ {
+ split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
+ split->gains_split = other;
+ return;
+ }
+
+ val = kvp_frame_get_slot (split->inst.kvp_data, "gains-source");
+ if (!val)
+ {
+ // FIXME: This looks bogus.
+ other = xaccSplitGetOtherSplit (split);
+ if (other)
+ val = kvp_frame_get_slot (other->inst.kvp_data, "gains-source");
+ split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
+ } else {
+ QofCollection *col;
+ col = qof_book_get_collection (split->inst.book, GNC_ID_SPLIT);
+ split->gains = GAINS_STATUS_GAINS;
+ other = (Split *) qof_collection_lookup_entity (col,
+ kvp_value_get_guid (val));
+ split->gains_split = other;
+ }
+}
+
+void mark_split (Split *s)
+{
+ Account *account = s->acc;
+
+ if (account && !account->inst.do_free)
+ {
+ account->balance_dirty = TRUE;
+ account->sort_dirty = TRUE;
+ }
+
+ /* set dirty flag on lot too. */
+ if (s->lot) s->lot->is_closed = -1;
+}
+
+void gen_event (const Split *split)
+{
+ Account *account = split->acc;
+ Transaction *trans = split->parent;
+ GNCLot *lot = split->lot;
+
+ if (account)
+ {
+ xaccGroupMarkNotSaved (account->parent);
+ gnc_engine_gen_event (&account->inst.entity, GNC_EVENT_MODIFY);
+ }
+
+ if (trans)
+ {
+ gnc_engine_gen_event (&trans->inst.entity, GNC_EVENT_MODIFY);
+ }
+
+ if (lot)
+ {
+ /* A change of value/amnt affects gains displat, etc. */
+ gnc_engine_gen_event (&lot->inst.entity, GNC_EVENT_MODIFY);
+ }
+}
+
+/********************************************************************\
+\********************************************************************/
+
+static inline int
+get_currency_denom(const Split * s)
+{
+ if (!s)
+ {
+ return 0;
+ }
+ else if(!s->parent || !s->parent->common_currency)
+ {
+ return 100000;
+ }
+ else
+ {
+ return gnc_commodity_get_fraction (s->parent->common_currency);
+ }
+}
+
+static inline int
+get_commodity_denom(const Split * s)
+{
+ if (!s)
+ {
+ return 0;
+ }
+ else if (!s->acc)
+ {
+ return 100000;
+ }
+ else
+ {
+ return xaccAccountGetCommoditySCU(s->acc);
+ }
+}
+
+/********************************************************************
+ * xaccSplitGetSlots
+ ********************************************************************/
+
+KvpFrame *
+xaccSplitGetSlots (const Split * s)
+{
+ return qof_instance_get_slots(QOF_INSTANCE(s));
+}
+
+void
+xaccSplitSetSlots_nc(Split *s, KvpFrame *frm)
+{
+ if (!s || !frm) return;
+ check_open (s->parent);
+
+ qof_instance_set_slots(QOF_INSTANCE(s), frm);
+}
+
+/********************************************************************\
+\********************************************************************/
+
+void
+DxaccSplitSetSharePriceAndAmount (Split *s, double price, double amt)
+{
+ if (!s) return;
+ ENTER (" ");
+ check_open (s->parent);
+
+ s->amount = double_to_gnc_numeric(amt, get_commodity_denom(s),
+ GNC_HOW_RND_ROUND);
+ s->value = double_to_gnc_numeric(price * amt, get_currency_denom(s),
+ GNC_HOW_RND_ROUND);
+
+ SET_GAINS_A_VDIRTY(s);
+ mark_split (s);
+}
+
+void
+xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)
+{
+ if (!s) return;
+ ENTER (" ");
+ check_open (s->parent);
+
+ s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
+ GNC_HOW_RND_ROUND);
+ s->value = gnc_numeric_mul(s->amount, price,
+ get_currency_denom(s), GNC_HOW_RND_ROUND);
+
+ SET_GAINS_A_VDIRTY(s);
+ mark_split (s);
+}
+
+static void
+qofSplitSetSharePrice (Split *split, gnc_numeric price)
+{
+ g_return_if_fail(split);
+ split->value = gnc_numeric_mul(xaccSplitGetAmount(split),
+ price, get_currency_denom(split),
+ GNC_HOW_RND_ROUND);
+}
+
+void
+xaccSplitSetSharePrice (Split *s, gnc_numeric price)
+{
+ if (!s) return;
+ ENTER (" ");
+ check_open (s->parent);
+
+ s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
+ price, get_currency_denom(s),
+ GNC_HOW_RND_ROUND);
+
+ SET_GAINS_VDIRTY(s);
+ mark_split (s);
+}
+
+void
+DxaccSplitSetShareAmount (Split *s, double damt)
+{
+ gnc_numeric old_price, old_amt;
+ int commodity_denom = get_commodity_denom(s);
+ gnc_numeric amt = double_to_gnc_numeric(damt, commodity_denom,
+ GNC_HOW_RND_ROUND);
+ if (!s) return;
+ ENTER (" ");
+ check_open (s->parent);
+
+ old_amt = xaccSplitGetAmount (s);
+ if (!gnc_numeric_zero_p(old_amt))
+ {
+ old_price = gnc_numeric_div(xaccSplitGetValue (s),
+ old_amt, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_REDUCE);
+ }
+ else {
+ old_price = gnc_numeric_create(1, 1);
+ }
+
+ s->amount = gnc_numeric_convert(amt, commodity_denom,
+ GNC_HOW_RND_NEVER);
+ s->value = gnc_numeric_mul(s->amount, old_price,
+ get_currency_denom(s), GNC_HOW_RND_ROUND);
+
+ SET_GAINS_A_VDIRTY(s);
+ mark_split (s);
+}
+
+static void
+qofSplitSetAmount (Split *split, gnc_numeric amt)
+{
+ g_return_if_fail(split);
+ if (split->acc)
+ {
+ split->amount = gnc_numeric_convert(amt,
+ get_commodity_denom(split), GNC_HOW_RND_ROUND);
+ }
+ else { split->amount = amt; }
+}
+
+/* The amount of the split in the _account's_ commodity. */
+void
+xaccSplitSetAmount (Split *s, gnc_numeric amt)
+{
+ if (!s) return;
+ g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
+ ENTER ("(split=%p) old amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
+ " new amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
+ s->amount.num, s->amount.denom, amt.num, amt.denom);
+
+ check_open (s->parent);
+ if (s->acc)
+ s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
+ GNC_HOW_RND_ROUND);
+ else
+ s->amount = amt;
+
+ SET_GAINS_ADIRTY(s);
+ mark_split (s);
+ LEAVE("");
+}
+
+static void
+qofSplitSetValue (Split *split, gnc_numeric amt)
+{
+ g_return_if_fail(split);
+ split->value = gnc_numeric_convert(amt,
+ get_currency_denom(split), GNC_HOW_RND_ROUND);
+}
+
+/* The value of the split in the _transaction's_ currency. */
+void
+xaccSplitSetValue (Split *s, gnc_numeric amt)
+{
+ if (!s) return;
+
+ g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
+ ENTER ("(split=%p) old val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
+ " new val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
+ s->value.num, s->value.denom, amt.num, amt.denom);
+
+ check_open (s->parent);
+ s->value = gnc_numeric_convert(amt, get_currency_denom(s),
+ GNC_HOW_RND_ROUND);
+
+ SET_GAINS_VDIRTY(s);
+ mark_split (s);
+ LEAVE ("");
+}
+
+/********************************************************************\
+\********************************************************************/
+
+gnc_numeric
+xaccSplitGetBalance (const Split *s)
+{
+ return s ? s->balance : gnc_numeric_zero();
+}
+
+gnc_numeric
+xaccSplitGetClearedBalance (const Split *s)
+{
+ return s ? s->cleared_balance : gnc_numeric_zero();
+}
+
+gnc_numeric
+xaccSplitGetReconciledBalance (const Split *s)
+{
+ return s ? s->reconciled_balance : gnc_numeric_zero();
+}
+
+void
+xaccSplitSetBaseValue (Split *s, gnc_numeric value,
+ const gnc_commodity * base_currency)
+{
+ const gnc_commodity *currency;
+ const gnc_commodity *commodity;
+
+ if (!s) return;
+ check_open (s->parent);
+
+ if (!s->acc)
+ {
+ PERR ("split must have a parent account");
+ return;
+ }
+
+ currency = xaccTransGetCurrency (s->parent);
+ commodity = xaccAccountGetCommodity (s->acc);
+
+ /* If the base_currency is the transaction's commodity ('currency'),
+ * set the value. If it's the account commodity, set the
+ * amount. If both, set both. */
+ if (gnc_commodity_equiv(currency, base_currency)) {
+ if (gnc_commodity_equiv(commodity, base_currency)) {
+ s->amount = gnc_numeric_convert(value,
+ get_commodity_denom(s),
+ GNC_HOW_RND_NEVER);
+ }
+ s->value = gnc_numeric_convert(value,
+ get_currency_denom(s),
+ GNC_HOW_RND_NEVER);
+ }
+ else if (gnc_commodity_equiv(commodity, base_currency)) {
+ s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
+ GNC_HOW_RND_NEVER);
+ }
+ else {
+ PERR ("inappropriate base currency %s "
+ "given split currency=%s and commodity=%s\n",
+ gnc_commodity_get_printname(base_currency),
+ gnc_commodity_get_printname(currency),
+ gnc_commodity_get_printname(commodity));
+ return;
+ }
+
+ SET_GAINS_A_VDIRTY(s);
+ mark_split (s);
+}
+
+gnc_numeric
+xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)
+{
+ if (!s || !s->acc || !s->parent) return gnc_numeric_zero();
+
+ /* be more precise -- the value depends on the currency we want it
+ * expressed in. */
+ if (gnc_commodity_equiv(xaccTransGetCurrency(s->parent), base_currency))
+ return xaccSplitGetValue(s);
+ if (gnc_commodity_equiv(xaccAccountGetCommodity(s->acc), base_currency))
+ return xaccSplitGetAmount(s);
+
+ PERR ("inappropriate base currency %s "
+ "given split currency=%s and commodity=%s\n",
+ gnc_commodity_get_printname(base_currency),
+ gnc_commodity_get_printname(xaccTransGetCurrency (s->parent)),
+ gnc_commodity_get_printname(xaccAccountGetCommodity(s->acc)));
+ return gnc_numeric_zero();
+}
+
+/********************************************************************\
+\********************************************************************/
+
+gnc_numeric
+xaccSplitsComputeValue (GList *splits, Split * skip_me,
+ const gnc_commodity * base_currency)
+{
+ GList *node;
+ gnc_numeric value = gnc_numeric_zero();
+
+ g_return_val_if_fail (base_currency, value);
+
+ ENTER (" currency=%s", gnc_commodity_get_mnemonic (base_currency));
+
+ for (node = splits; node; node = node->next)
+ {
+ Split *s = node->data;
+ const gnc_commodity *currency;
+ const gnc_commodity *commodity;
+
+ if (s == skip_me) continue;
+
+ /* value = gnc_numeric_add(value, xaccSplitGetBaseValue(s, base_currency),
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); */
+
+ /* The split-editor often sends us 'temp' splits whose account
+ * hasn't yet been set. Be lenient, and assume an implied base
+ * currency. If there's a problem later, the scrub routines will
+ * pick it up.
+ */
+ commodity = s->acc ? xaccAccountGetCommodity (s->acc) : base_currency;
+ currency = xaccTransGetCurrency (s->parent);
+
+
+ if (gnc_commodity_equiv(currency, base_currency))
+ {
+ value = gnc_numeric_add(value, xaccSplitGetValue(s),
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
+ }
+ else if (gnc_commodity_equiv(commodity, base_currency))
+ {
+ value = gnc_numeric_add(value, xaccSplitGetAmount(s),
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
+ }
+ else {
+ PERR ("inconsistent currencies\n"
+ "\tbase = '%s', curr='%s', sec='%s'\n",
+ gnc_commodity_get_printname(base_currency),
+ gnc_commodity_get_printname(currency),
+ gnc_commodity_get_printname(commodity));
+ g_return_val_if_fail (FALSE, value);
+ }
+ }
+
+ /* Note that just because the currencies are equivalent
+ * doesn't mean the denominators are the same! */
+ value = gnc_numeric_convert(value,
+ gnc_commodity_get_fraction (base_currency),
+ GNC_HOW_RND_ROUND);
+
+ LEAVE (" total=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
+ value.num, value.denom);
+ return value;
+}
+
+gnc_numeric
+xaccSplitConvertAmount (Split *split, Account * account)
+{
+ gnc_commodity *acc_com, *to_commodity;
+ Transaction *txn;
+ gnc_numeric amount, value, convrate;
+ Account * split_acc;
+
+ amount = xaccSplitGetAmount (split);
+
+ /* If this split is attached to this account, OR */
+ split_acc = xaccSplitGetAccount (split);
+ if (split_acc == account)
+ return amount;
+
+ /* If split->account->commodity == to_commodity, return the amount */
+ acc_com = xaccAccountGetCommodity (split_acc);
+ to_commodity = xaccAccountGetCommodity (account);
+ if (acc_com && gnc_commodity_equal (acc_com, to_commodity))
+ return amount;
+
+ /* Ok, this split is not for the viewed account, and the commodity
+ * does not match. So we need to do some conversion.
+ *
+ * First, we can cheat. If this transaction is balanced and has
+ * exactly two splits, then we can implicitly determine the exchange
+ * rate and just return the 'other' split amount.
+ */
+ txn = xaccSplitGetParent (split);
+ if (txn && gnc_numeric_zero_p (xaccTransGetImbalance (txn))) {
+ Split *osplit = xaccSplitGetOtherSplit (split);
+
+ if (osplit)
+ return gnc_numeric_neg (xaccSplitGetAmount (osplit));
+ }
+
+ /* ... otherwise, we need to compute the amount from the conversion
+ * rate into _this account_. So, find the split into this account,
+ * compute the conversion rate (based on amount/value), and then multiply
+ * this times the split value.
+ */
+ convrate = xaccTransGetAccountConvRate(txn, account);
+ value = xaccSplitGetValue (split);
+ return gnc_numeric_mul (value, convrate,
+ gnc_commodity_get_fraction (to_commodity),
+ GNC_RND_ROUND);
+}
+
+/********************************************************************\
+\********************************************************************/
+
+gboolean
+xaccSplitDestroy (Split *split)
+{
+ Account *acc;
+ Transaction *trans;
+
+ if (!split) return TRUE;
+
+ acc = split->acc;
+ trans = split->parent;
+ if (acc && !acc->inst.do_free && xaccTransGetReadOnly (trans))
+ return FALSE;
+
+ check_open (trans);
+
+ mark_split (split);
+
+ if (trans)
+ {
+ if (g_list_find(trans->splits, split))
+ xaccTransRemoveSplit (trans, split);
+ else
+ PERR ("split not in transaction");
+ }
+
+ /* Note: split is removed from lot when it's removed from account */
+ xaccAccountRemoveSplit (acc, split);
+
+ /* If we're shutting down then destroy the transaction, too, and
+ * don't recompute the balance.
+ */
+ if (qof_book_shutting_down (split->parent->inst.book))
+ /* This seems like an odd place to do this. Transactions have
+ to be opened to destroy them. */
+ xaccTransDestroy (trans);
+ else
+ /* This seems a bit eager. Isn't there a lazy way to do this? */
+ xaccAccountRecomputeBalance (acc);
+
+
+ gen_event (split);
+ xaccFreeSplit (split);
+ return TRUE;
+}
+
+/********************************************************************\
+\********************************************************************/
+
+int
+xaccSplitDateOrder (const Split *sa, const Split *sb)
+{
+ int retval;
+ int comp;
+ char *da, *db;
+
+ if (sa == sb) return 0;
+ /* nothing is always less than something */
+ if (!sa && sb) return -1;
+ if (sa && !sb) return +1;
+
+ retval = xaccTransOrder (sa->parent, sb->parent);
+ if (retval) return retval;
+
+ /* otherwise, sort on memo strings */
+ da = sa->memo;
+ db = sb->memo;
+ SAFE_STRCMP (da, db);
+
+ /* otherwise, sort on action strings */
+ da = sa->action;
+ db = sb->action;
+ SAFE_STRCMP (da, db);
+
+ /* the reconciled flag ... */
+ if (sa->reconciled < sb->reconciled) return -1;
+ if (sa->reconciled > sb->reconciled) return +1;
+
+ /* compare amounts */
+ comp = gnc_numeric_compare(xaccSplitGetAmount(sa), xaccSplitGetAmount (sb));
+ if (comp < 0) return -1;
+ if (comp > 0) return +1;
+
+ comp = gnc_numeric_compare(xaccSplitGetValue(sa), xaccSplitGetValue (sb));
+ if (comp < 0) return -1;
+ if (comp > 0) return +1;
+
+ /* if dates differ, return */
+ DATE_CMP(sa,sb,date_reconciled);
+
+ /* else, sort on guid - keeps sort stable. */
+ retval = guid_compare(&(sa->inst.entity.guid), &(sb->inst.entity.guid));
+ if (retval) return retval;
+
+ return 0;
+}
+
+static gboolean
+get_corr_account_split(const Split *sa, Split **retval)
+{
+
+ Split *current_split;
+ GList *node;
+ gnc_numeric sa_value, current_value;
+ gboolean sa_value_positive, current_value_positive, seen_different = FALSE;
+
+ *retval = NULL;
+ g_return_val_if_fail(sa, TRUE);
+
+ sa_value = xaccSplitGetValue (sa);
+ sa_value_positive = gnc_numeric_positive_p(sa_value);
+
+ for (node = sa->parent->splits; node; node = node->next)
+ {
+ current_split = node->data;
+ if (current_split == sa) continue;
+
+ current_value = xaccSplitGetValue (current_split);
+ current_value_positive = gnc_numeric_positive_p(current_value);
+ if ((sa_value_positive && !current_value_positive) ||
+ (!sa_value_positive && current_value_positive)) {
+ if (seen_different) {
+ *retval = NULL;
+ return TRUE;
+ } else {
+ *retval = current_split;
+ seen_different = TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/* TODO: these static consts can be shared. */
+const char *
+xaccSplitGetCorrAccountName(const Split *sa)
+{
+ static const char *split_const = NULL;
+ Split *other_split;
+
+ if (get_corr_account_split(sa, &other_split))
+ {
+ if (!split_const)
+ split_const = _("-- Split Transaction --");
+
+ return split_const;
+ }
+
+ return xaccAccountGetName(other_split->acc);
+}
+
+char *
+xaccSplitGetCorrAccountFullName(const Split *sa, char separator)
+{
+ static const char *split_const = NULL;
+ Split *other_split;
+
+ if (get_corr_account_split(sa, &other_split))
+ {
+ if (!split_const)
+ split_const = _("-- Split Transaction --");
+
+ return g_strdup(split_const);
+ }
+ return xaccAccountGetFullName(other_split->acc, separator);
+}
+
+const char *
+xaccSplitGetCorrAccountCode(const Split *sa)
+{
+ static const char *split_const = NULL;
+ Split *other_split;
+
+ if (get_corr_account_split(sa, &other_split))
+ {
+ if (!split_const)
+ split_const = _("Split");
+
+ return split_const;
+ }
+ return xaccAccountGetCode(other_split->acc);
+}
+
+/* TODO: It's not too hard to make this function avoid the malloc/free. */
+int
+xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
+{
+ Account *aa, *ab;
+ char *full_a, *full_b;
+ int retval;
+ if (!sa && !sb) return 0;
+ if (!sa) return -1;
+ if (!sb) return 1;
+
+ aa = sa->acc;
+ ab = sb->acc;
+ full_a = xaccAccountGetFullName(aa, ':');
+ full_b = xaccAccountGetFullName(ab, ':');
+ /* for comparison purposes it doesn't matter what we use as a separator */
+ retval = safe_strcmp(full_a, full_b);
+ g_free(full_a);
+ g_free(full_b);
+ return retval;
+}
+
+
+int
+xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
+{
+ Account *aa, *ab;
+ if (!sa && !sb) return 0;
+ if (!sa) return -1;
+ if (!sb) return 1;
+
+ aa = sa->acc;
+ ab = sb->acc;
+
+ return safe_strcmp(xaccAccountGetName(aa), xaccAccountGetName(ab));
+}
+
+int
+xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
+{
+ char *ca, *cb;
+ int retval;
+ if (!sa && !sb) return 0;
+ if (!sa) return -1;
+ if (!sb) return 1;
+
+ /* doesn't matter what separator we use
+ * as long as they are the same
+ */
+
+ ca = xaccSplitGetCorrAccountFullName(sa, ':');
+ cb = xaccSplitGetCorrAccountFullName(sb, ':');
+ retval = safe_strcmp(ca, cb);
+ g_free(ca);
+ g_free(cb);
+ return retval;
+}
+
+int
+xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
+{
+ const char *ca, *cb;
+ if (!sa && !sb) return 0;
+ if (!sa) return -1;
+ if (!sb) return 1;
+
+ ca = xaccSplitGetCorrAccountCode(sa);
+ cb = xaccSplitGetCorrAccountCode(sb);
+ return safe_strcmp(ca, cb);
+}
+
+static void
+qofSplitSetMemo (Split *split, const char* memo)
+{
+ gchar *tmp;
+
+ g_return_if_fail(split);
+ tmp = gnc_string_cache_insert((gpointer) memo);
+ gnc_string_cache_remove(split->memo);
+ split->memo = tmp;
+}
+
+void
+xaccSplitSetMemo (Split *split, const char *memo)
+{
+ char * tmp;
+ if (!split || !memo) return;
+ check_open (split->parent);
+
+ tmp = gnc_string_cache_insert((gpointer) memo);
+ gnc_string_cache_remove(split->memo);
+ split->memo = tmp;
+}
+
+static void
+qofSplitSetAction (Split *split, const char *actn)
+{
+ g_return_if_fail(split);
+ split->action = g_strdup(actn);
+}
+
+void
+xaccSplitSetAction (Split *split, const char *actn)
+{
+ char * tmp;
+ if (!split || !actn) return;
+ check_open (split->parent);
+
+ tmp = gnc_string_cache_insert((gpointer) actn);
+ gnc_string_cache_remove(split->action);
+ split->action = tmp;
+}
+
+static void
+qofSplitSetReconcile (Split *split, char recn)
+{
+ g_return_if_fail(split);
+ switch (recn)
+ {
+ case NREC:
+ case CREC:
+ case YREC:
+ case FREC:
+ case VREC:
+ split->reconciled = recn;
+ mark_split (split);
+ xaccAccountRecomputeBalance (split->acc);
+ break;
+ default:
+ PERR("Bad reconciled flag");
+ }
+}
+
+void
+xaccSplitSetReconcile (Split *split, char recn)
+{
+ if (!split || split->reconciled == recn) return;
+ check_open (split->parent);
+
+ switch (recn)
+ {
+ case NREC:
+ case CREC:
+ case YREC:
+ case FREC:
+ case VREC:
+ split->reconciled = recn;
+ mark_split (split);
+ xaccAccountRecomputeBalance (split->acc);
+ break;
+ default:
+ PERR("Bad reconciled flag");
+ }
+}
+
+void
+xaccSplitSetDateReconciledSecs (Split *split, time_t secs)
+{
+ if (!split) return;
+ check_open (split->parent);
+
+ split->date_reconciled.tv_sec = secs;
+ split->date_reconciled.tv_nsec = 0;
+}
+
+void
+xaccSplitSetDateReconciledTS (Split *split, Timespec *ts)
+{
+ if (!split || !ts) return;
+ check_open (split->parent);
+
+ split->date_reconciled = *ts;
+}
+
+void
+xaccSplitGetDateReconciledTS (const Split * split, Timespec *ts)
+{
+ if (!split || !ts) return;
+ *ts = (split->date_reconciled);
+}
+
+Timespec
+xaccSplitRetDateReconciledTS (const Split * split)
+{
+ Timespec ts = {0,0};
+ return split ? split->date_reconciled : ts;
+}
+
+/********************************************************************\
+\********************************************************************/
+
+/* return the parent transaction of the split */
+Transaction *
+xaccSplitGetParent (const Split *split)
+{
+ return split ? split->parent : NULL;
+}
+
+GNCLot *
+xaccSplitGetLot (const Split *split)
+{
+ return split ? split->lot : NULL;
+}
+
+const char *
+xaccSplitGetMemo (const Split *split)
+{
+ return split ? split->memo : NULL;
+}
+
+const char *
+xaccSplitGetAction (const Split *split)
+{
+ return split ? split->action : NULL;
+}
+
+char
+xaccSplitGetReconcile (const Split *split)
+{
+ return split ? split->reconciled : ' ';
+}
+
+
+gnc_numeric
+xaccSplitGetAmount (const Split * split)
+{
+ return split ? split->amount : gnc_numeric_zero();
+}
+
+gnc_numeric
+xaccSplitGetValue (const Split * split)
+{
+ return split ? split->value : gnc_numeric_zero();
+}
+
+gnc_numeric
+xaccSplitGetSharePrice (const Split * split)
+{
+ gnc_numeric amt, val, price;
+ if (!split) return gnc_numeric_create(1, 1);
+
+
+ /* if amount == 0 and value == 0, then return 1.
+ * if amount == 0 and value != 0 then return 0.
+ * otherwise return value/amount
+ */
+
+ amt = xaccSplitGetAmount(split);
+ val = xaccSplitGetValue(split);
+ if (gnc_numeric_zero_p(amt))
+ {
+ if (gnc_numeric_zero_p(val))
+ return gnc_numeric_create(1, 1);
+ return gnc_numeric_create(0, 1);
+ }
+ price = gnc_numeric_div(val, amt,
+ GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(PRICE_SIGFIGS) |
+ GNC_HOW_RND_ROUND);
+
+ /* During random checks we can get some very weird prices. Let's
+ * handle some overflow and other error conditions by returning
+ * zero. But still print an error to let us know it happened.
+ */
+ if (gnc_numeric_check(price))
+ {
+ PERR("Computing share price failed (%d): [ %" G_GINT64_FORMAT " / %"
+ G_GINT64_FORMAT " ] / [ %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " ]",
+ gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
+ return gnc_numeric_create(0,1);
+ }
+
+ return price;
+}
+
+/********************************************************************\
+\********************************************************************/
+
+QofBook *
+xaccSplitGetBook (const Split *split)
+{
+ return qof_instance_get_book(QOF_INSTANCE(split));
+}
+
+const char *
+xaccSplitGetType(const Split *s)
+{
+ char *split_type;
+
+ if (!s) return NULL;
+ split_type = kvp_frame_get_string(s->inst.kvp_data, "split-type");
+ return split_type ? split_type : "normal";
+}
+
+/* reconfigure a split to be a stock split - after this, you shouldn't
+ mess with the value, just the amount. */
+void
+xaccSplitMakeStockSplit(Split *s)
+{
+ check_open (s->parent);
+
+ s->value = gnc_numeric_zero();
+ kvp_frame_set_str(s->inst.kvp_data, "split-type", "stock-split");
+ SET_GAINS_VDIRTY(s);
+ mark_split(s);
+}
+
+
+/********************************************************************\
+\********************************************************************/
+/* In the old world, the 'other split' was the other split of a
+ * transaction that contained only two splits. In the new world,
+ * a split may have been cut up between multiple lots, although
+ * in a conceptual sense, if lots hadn't been used, there would be
+ * only a pair. So we handle this conceptual case: we can still
+ * identify, unambiguously, the 'other' split when 'this' split
+ * as been cut up across lots. We do this by looking for the
+ * 'lot-split' keyword, which occurs only in cut-up splits.
+ */
+
+Split *
+xaccSplitGetOtherSplit (const Split *split)
+{
+ SplitList *node;
+ Transaction *trans;
+ int count;
+ Split *other = NULL;
+ KvpValue *sva;
+
+ if (!split) return NULL;
+ trans = split->parent;
+ if (!trans) return NULL;
+
+#ifdef OLD_ALGO_HAS_ONLY_TWO_SPLITS
+ Split *s1, *s2;
+ if (g_list_length (trans->splits) != 2) return NULL;
+
+ s1 = g_list_nth_data (trans->splits, 0);
+ s2 = g_list_nth_data (trans->splits, 1);
+
+ if (s1 == split) return s2;
+ return s1;
+#endif
+
+ count = g_list_length (trans->splits);
+ sva = kvp_frame_get_slot (split->inst.kvp_data, "lot-split");
+ if (!sva && (2 != count)) return NULL;
+
+ for (node = trans->splits; node; node = node->next)
+ {
+ Split *s = node->data;
+ if (s == split) { --count; continue; }
+ if (kvp_frame_get_slot (s->inst.kvp_data, "lot-split")) { --count; continue; }
+ other = s;
+ }
+ return (1 == count) ? other : NULL;
+}
+
+/********************************************************************\
+\********************************************************************/
+
+gboolean
+xaccIsPeerSplit (const Split *sa, const Split *sb)
+{
+ return (sa && sb && (sa->parent == sb->parent));
+}
+
+gnc_numeric
+xaccSplitVoidFormerAmount(const Split *split)
+{
+ g_return_val_if_fail(split, gnc_numeric_zero());
+ return kvp_frame_get_numeric(split->inst.kvp_data, void_former_amt_str);
+}
+
+gnc_numeric
+xaccSplitVoidFormerValue(const Split *split)
+{
+ g_return_val_if_fail(split, gnc_numeric_zero());
+ return kvp_frame_get_numeric(split->inst.kvp_data, void_former_val_str);
+}
+
+void
+xaccSplitVoid(Split *split)
+{
+ gnc_numeric zero = gnc_numeric_zero();
+ KvpFrame *frame = split->inst.kvp_data;
+
+ kvp_frame_set_gnc_numeric(frame, void_former_amt_str,
+ xaccSplitGetAmount(split));
+ kvp_frame_set_gnc_numeric(frame, void_former_val_str,
+ xaccSplitGetValue(split));
+
+ xaccSplitSetAmount (split, zero);
+ xaccSplitSetValue (split, zero);
+ xaccSplitSetReconcile(split, VREC);
+
+}
+
+void
+xaccSplitUnvoid(Split *split)
+{
+ KvpFrame *frame = split->inst.kvp_data;
+
+ xaccSplitSetAmount (split, xaccSplitVoidFormerAmount(split));
+ xaccSplitSetValue (split, xaccSplitVoidFormerValue(split));
+ xaccSplitSetReconcile(split, NREC);
+ kvp_frame_set_slot(frame, void_former_amt_str, NULL);
+ kvp_frame_set_slot(frame, void_former_val_str, NULL);
+}
+
+/********************************************************************\
+\********************************************************************/
+/* QofObject function implementation */
+
+/* Hook into the QofObject registry */
+
+static QofObject split_object_def = {
+ interface_version: QOF_OBJECT_VERSION,
+ e_type: GNC_ID_SPLIT,
+ type_label: "Split",
+ create: (gpointer)xaccMallocSplit,
+ book_begin: NULL,
+ book_end: NULL,
+ is_dirty: NULL,
+ mark_clean: NULL,
+ foreach: qof_collection_foreach,
+ printable: (const char* (*)(gpointer)) xaccSplitGetMemo,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
+};
+
+static gpointer
+split_account_guid_getter (gpointer obj, const QofParam *p)
+{
+ Split *s = obj;
+ Account *acc;
+
+ if (!s) return NULL;
+ acc = xaccSplitGetAccount (s);
+ if (!acc) return NULL;
+ return ((gpointer)xaccAccountGetGUID (acc));
+}
+
+static double /* internal use only */
+DxaccSplitGetShareAmount (const Split * split)
+{
+ return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
+}
+
+static gpointer
+no_op (gpointer obj, const QofParam *p)
+{
+ return obj;
+}
+
+static void
+qofSplitSetParentTrans(Split *s, QofEntity *ent)
+{
+ Transaction *trans = (Transaction*)ent;
+
+ g_return_if_fail(trans);
+ xaccTransAppendSplit(trans, s);
+}
+
+static void
+qofSplitSetAccount(Split *s, QofEntity *ent)
+{
+ Account *acc = (Account*)ent;
+
+ g_return_if_fail(acc);
+ xaccAccountInsertSplit(acc, s);
+}
+
+gboolean xaccSplitRegister (void)
+{
+ static const QofParam params[] = {
+ { SPLIT_DATE_RECONCILED, QOF_TYPE_DATE,
+ (QofAccessFunc)xaccSplitRetDateReconciledTS,
+ (QofSetterFunc)xaccSplitSetDateReconciledTS },
+
+ /* d-* are deprecated query params, should not be used in new
+ * queries, should be removed from old queries. */
+ { "d-share-amount", QOF_TYPE_DOUBLE,
+ (QofAccessFunc)DxaccSplitGetShareAmount, NULL },
+ { "d-share-int64", QOF_TYPE_INT64,
+ (QofAccessFunc)qof_entity_get_guid, NULL },
+ { SPLIT_BALANCE, QOF_TYPE_NUMERIC,
+ (QofAccessFunc)xaccSplitGetBalance, NULL },
+ { SPLIT_CLEARED_BALANCE, QOF_TYPE_NUMERIC,
+ (QofAccessFunc)xaccSplitGetClearedBalance, NULL },
+ { SPLIT_RECONCILED_BALANCE, QOF_TYPE_NUMERIC,
+ (QofAccessFunc)xaccSplitGetReconciledBalance, NULL },
+ { SPLIT_MEMO, QOF_TYPE_STRING,
+ (QofAccessFunc)xaccSplitGetMemo, (QofSetterFunc)qofSplitSetMemo },
+ { SPLIT_ACTION, QOF_TYPE_STRING,
+ (QofAccessFunc)xaccSplitGetAction, (QofSetterFunc)qofSplitSetAction },
+ { SPLIT_RECONCILE, QOF_TYPE_CHAR,
+ (QofAccessFunc)xaccSplitGetReconcile,
+ (QofSetterFunc)qofSplitSetReconcile },
+ { SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
+ (QofAccessFunc)xaccSplitGetAmount, (QofSetterFunc)qofSplitSetAmount },
+ { SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
+ (QofAccessFunc)xaccSplitGetSharePrice,
+ (QofSetterFunc)qofSplitSetSharePrice },
+ { SPLIT_VALUE, QOF_TYPE_DEBCRED,
+ (QofAccessFunc)xaccSplitGetValue, (QofSetterFunc)qofSplitSetValue },
+ { SPLIT_TYPE, QOF_TYPE_STRING, (QofAccessFunc)xaccSplitGetType, NULL },
+ { SPLIT_VOIDED_AMOUNT, QOF_TYPE_NUMERIC,
+ (QofAccessFunc)xaccSplitVoidFormerAmount, NULL },
+ { SPLIT_VOIDED_VALUE, QOF_TYPE_NUMERIC,
+ (QofAccessFunc)xaccSplitVoidFormerValue, NULL },
+ { SPLIT_LOT, GNC_ID_LOT, (QofAccessFunc)xaccSplitGetLot, NULL },
+ { SPLIT_TRANS, GNC_ID_TRANS,
+ (QofAccessFunc)xaccSplitGetParent,
+ (QofSetterFunc)qofSplitSetParentTrans },
+ { SPLIT_ACCOUNT, GNC_ID_ACCOUNT,
+ (QofAccessFunc)xaccSplitGetAccount, (QofSetterFunc)qofSplitSetAccount },
+ { SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, NULL },
+/* these are no-ops to register the parameter names (for sorting) but
+ they return an allocated object which getters cannot do. */
+ { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, NULL },
+ { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, NULL },
+ { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, NULL },
+ { SPLIT_KVP, QOF_TYPE_KVP, (QofAccessFunc)xaccSplitGetSlots, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID,
+ (QofAccessFunc)qof_entity_get_guid, NULL },
+ { NULL },
+ };
+
+ qof_class_register (GNC_ID_SPLIT, (QofSortFunc)xaccSplitDateOrder, params);
+ qof_class_register (SPLIT_ACCT_FULLNAME,
+ (QofSortFunc)xaccSplitCompareAccountFullNames, NULL);
+ qof_class_register (SPLIT_CORR_ACCT_NAME,
+ (QofSortFunc)xaccSplitCompareOtherAccountFullNames,
+ NULL);
+ qof_class_register (SPLIT_CORR_ACCT_CODE,
+ (QofSortFunc)xaccSplitCompareOtherAccountCodes, NULL);
+
+ return qof_object_register (&split_object_def);
+}
+
+/************************ END OF ************************************\
+\************************* FILE *************************************/
Copied: gnucash/trunk/src/engine/Split.h (from rev 13359, gnucash/trunk/src/engine/Transaction.h)
===================================================================
--- gnucash/trunk/src/engine/Transaction.h 2006-02-22 06:01:07 UTC (rev 13359)
+++ gnucash/trunk/src/engine/Split.h 2006-02-22 21:52:46 UTC (rev 13363)
@@ -0,0 +1,490 @@
+/********************************************************************\
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+/** @addtogroup Engine
+ @{ */
+/** @addtogroup Transaction Financial Transactions
+ A good overview of transactions, splits and accounts can be
+ found in the texinfo documentation, together with an overview of
+ how to use this API.
+
+ @{ */
+/** @file Split.h
+ @brief API for Transactions and Splits (journal entries)
+ @author Copyright (C) 1997 Robin D. Clark
+ @author Copyright (C) 1997-2001 Linas Vepstas <linas at linas.org>
+*/
+
+#ifndef XACC_SPLIT_H
+#define XACC_SPLIT_H
+
+#include <time.h>
+
+#include "gnc-commodity.h"
+#include "gnc-engine.h"
+
+/** @name Split Reconciled field values
+
+ If you change these
+ be sure to change gnc-ui-util.c:gnc_get_reconciled_str() and
+ associated functions
+
+@{
+*/
+#define CREC 'c' /**< The Split has been cleared */
+#define YREC 'y' /**< The Split has been reconciled */
+#define FREC 'f' /**< frozen into accounting period */
+#define NREC 'n' /**< not reconciled or cleared */
+#define VREC 'v' /**< split is void */
+/** @} */
+
+/* Convert the amount/value of the Split for viewing in the account --
+ * in particular we want to convert the Split to be in to_commodity.
+ * Returns the amount.
+ */
+gnc_numeric xaccSplitConvertAmount (Split *split, Account * account);
+
+/*-----------------------------------------------------------------------
+ * Splits
+ *-----------------------------------------------------------------------*/
+
+/** @name Split general getters/setters
+@{
+*/
+
+/** Constructor. */
+Split * xaccMallocSplit (QofBook *book);
+
+/* Reinit a previously malloc'd split. Split remains in the book it
+ was already in, and the QofEntity portions also remain unchanged.
+ It's basically the data elements that are reverted to default
+ values. */
+void xaccSplitReinit(Split * split);
+
+/** Destructor.
+ *
+ * The xaccSplitDestroy() method will update its parent account and
+ * transaction in a consistent manner, resulting in the complete
+ * unlinking of the split, and the freeing of its associated memory.
+ * The goal of this routine is to perform the removal and destruction
+ * of the split in an atomic fashion, with no chance of accidentally
+ * leaving the accounting structure out-of-balance or otherwise
+ * inconsistent.
+ *
+ * If the deletion of the split leaves the transaction with no splits,
+ * then the transaction will be marked for deletion. (It will not be
+ * deleted until the xaccTransCommitEdit() routine is called.)
+ *
+ * @return TRUE upon successful deletion of the split. FALSE when
+ * the parenting Transaction is a read-only one.
+ */
+gboolean xaccSplitDestroy (Split *split);
+
+/** Returns the book of this split, i.e. the entity where this split
+ * is stored. */
+QofBook * xaccSplitGetBook (const Split *split);
+
+/** Returns the account of this split, which was set through
+ * xaccAccountInsertSplit(). */
+Account * xaccSplitGetAccount (const Split *split);
+
+/** Returns the parent transaction of the split, which was set through
+ * xaccTransAppendSplit(). */
+Transaction * xaccSplitGetParent (const Split *split);
+
+/** Returns the pointer to the debited/credited Lot where this split
+ * belongs to, or NULL if it doesn't belong to any. */
+GNCLot * xaccSplitGetLot (const Split *split);
+
+
+/** Returns the KvpFrame slots of this split for direct editing.
+ *
+ * Split slots are used to store arbitrary strings, numbers, and
+ * structures which aren't members of the transaction struct. See
+ * kvp_doc.txt for reserved slot names.
+ */
+KvpFrame *xaccSplitGetSlots(const Split *split);
+
+/** Set the KvpFrame slots of this split to the given frm by directly
+ * using the frm pointer (i.e. non-copying). */
+void xaccSplitSetSlots_nc(Split *s, KvpFrame *frm);
+
+
+/** The memo is an arbitrary string associated with a split. It is
+ * intended to hold a short (zero to forty character) string that is
+ * displayed by the GUI along with this split. Users typically type
+ * in free form text from the GUI. */
+void xaccSplitSetMemo (Split *split, const char *memo);
+
+/** Returns the memo string. */
+const char * xaccSplitGetMemo (const Split *split);
+
+/** The Action is an arbitrary user-assigned string.
+ * The action field is an arbitrary user-assigned value.
+ * It is meant to be a very short (one to ten cahracter) string that
+ * signifies the "type" of this split, such as e.g. Buy, Sell, Div,
+ * Withdraw, Deposit, ATM, Check, etc. The idea is that this field
+ * can be used to create custom reports or graphs of data. */
+void xaccSplitSetAction (Split *split, const char *action);
+
+/** Returns the action string. */
+const char * xaccSplitGetAction (const Split *split);
+/** @} */
+
+/** @name Split Date getters/setters
+@{
+*/
+/** Set the reconcile flag. The Reconcile flag is a single char, whose
+ * values are typically are 'n', 'y', 'c'. In Transaction.h, macros
+ * are defined for typical values (e.g. CREC, YREC). */
+void xaccSplitSetReconcile (Split *split, char reconciled_flag);
+/** Returns the value of the reconcile flag. */
+char xaccSplitGetReconcile (const Split *split);
+
+/** Set the date on which this split was reconciled by specifying the
+ * time as time_t. */
+void xaccSplitSetDateReconciledSecs (Split *split, time_t time);
+/** Set the date on which this split was reconciled by specifying the
+ * time as Timespec. */
+void xaccSplitSetDateReconciledTS (Split *split, Timespec *ts);
+/** Get the date on which this split was reconciled by having it
+ * written into the Timespec that 'ts' is pointing to. */
+void xaccSplitGetDateReconciledTS (const Split *split,
+ Timespec *ts);
+/** Returns the date (as Timespec) on which this split was reconciled. */
+Timespec xaccSplitRetDateReconciledTS (const Split *split);
+
+/** @} */
+
+
+/** @name Split amount getters/setters
+ *
+ * 'value' vs. 'amount' of a Split: The 'value' is the amount of the
+ * _transaction_ balancing commodity (i.e. currency) involved,
+ * 'amount' is the amount of the _account's_ commodity involved.
+@{
+*/
+
+/** The xaccSplitSetAmount() method sets the amount in the account's
+ * commodity that the split should have.
+ *
+ * The following four setter functions set the prices and amounts.
+ * All of the routines always maintain balance: that is, invoking any
+ * of them will cause other splits in the transaction to be modified
+ * so that the net value of the transaction is zero.
+ *
+ * IMPORTANT: The split should be parented by an account before
+ * any of these routines are invoked! This is because the actual
+ * setting of amounts/values requires SCU settings from the account.
+ * If these are not available, then amounts/values will be set to
+ * -1/0, which is an invalid value. I beleive this order dependency
+ * is a bug, but I'm too lazy to find, fix & test at the moment ...
+ *
+ * @note If you use this on a newly created transaction, make sure
+ * that the 'value' is also set so that it doesn't remain zero.
+ */
+void xaccSplitSetAmount (Split *split, gnc_numeric amount);
+
+/** Returns the amount of the split in the account's commodity.
+ * Note that for cap-gains splits, this is slaved to the transaction
+ * that is causing the gains to occur.
+ */
+gnc_numeric xaccSplitGetAmount (const Split * split);
+
+/** The xaccSplitSetValue() method sets the value of this split in the
+ * transaction's commodity.
+ *
+ * @note If you use this on a newly created transaction, make sure
+ * that the 'amount' is also set so that it doesn't remain zero.
+ */
+void xaccSplitSetValue (Split *split, gnc_numeric value);
+
+/** Returns the value of this split in the transaction's commodity.
+ * Note that for cap-gains splits, this is slaved to the transaction
+ * that is causing the gains to occur.
+*/
+gnc_numeric xaccSplitGetValue (const Split * split);
+
+/** The xaccSplitSetSharePriceAndAmount() method will simultaneously
+ * update the share price and the number of shares. This is a utility
+ * routine that is equivalent to a xaccSplitSetSharePrice() followed
+ * by and xaccSplitSetAmount(), except that it incurs the processing
+ * overhead of balancing only once, instead of twice. */
+void xaccSplitSetSharePriceAndAmount (Split *split,
+ gnc_numeric price,
+ gnc_numeric amount);
+
+/** Returns the price of the split, that is, the value divided by the
+ * amount. If the amount is zero, returns a gnc_numeric of value
+ * one. */
+gnc_numeric xaccSplitGetSharePrice (const Split * split);
+
+/** Depending on the base_currency, set either the value or the amount
+ * of this split or both: If the base_currency is the transaction's
+ * commodity, set the value. If it is the account's commodity, set the
+ * amount. If both, set both.
+ *
+ * @note <b>WATCH OUT:</b> When using this function and the
+ * transaction's and account's commodities are different, the amount
+ * or the value will be left as zero. This might screw up the
+ * multi-currency handling code in the register. So please think twice
+ * whether you need this function -- using xaccSplitSetValue()
+ * together with xaccSplitSetAmount() is definitely the better and
+ * safer solution!
+ */
+void xaccSplitSetBaseValue (Split *split, gnc_numeric value,
+ const gnc_commodity * base_currency);
+
+/** Depending on the base_currency, return either the value or the
+ * amount of this split: If the base_curreny is the transaction's
+ * commodity, return the value. If it is the account's commodity,
+ * return the amount. If it is neither print a warning message and
+ * return gnc_numeric_zero().
+ */
+gnc_numeric xaccSplitGetBaseValue (const Split *split,
+ const gnc_commodity * base_currency);
+
+/** Returns the running balance up to and including the indicated split.
+ * The balance is the currency-denominated balance. For accounts
+ * with non-unit share prices, it is correctly adjusted for
+ * share prices.
+ *
+ * Returns the running balance up to & including the indicated split.
+ */
+gnc_numeric xaccSplitGetBalance (const Split *split);
+
+/**
+ * The cleared-balance is the currency-denominated balance
+ * of all transactions that have been marked as cleared or reconciled.
+ * It is correctly adjusted for price fluctuations.
+ *
+ * Returns the running balance up to & including the indicated split.
+ */
+gnc_numeric xaccSplitGetClearedBalance (const Split *split);
+
+/**
+ * Returns the reconciled-balance of this split. The
+ * reconciled-balance is the currency-denominated balance of all
+ * transactions that have been marked as reconciled.
+ *
+ * Returns the running balance up to & including the indicated split.
+ */
+gnc_numeric xaccSplitGetReconciledBalance (const Split *split);
+
+/** @} */
+
+/** @name Split utility functions
+@{
+*/
+
+/* Get a GList of unique transactions containing the given list of Splits. */
+GList *xaccSplitListGetUniqueTransactions(const GList *splits);
+
+/** Equality.
+ *
+ * @param sa First split to compare
+ * @param sb Second split to compare
+ *
+ * @param check_guids If TRUE, try a guid_equal() on the GUIDs of both
+ * splits if their pointers are not equal in the first place.
+ *
+ * @param check_balances If TRUE, compare balances between the two
+ * splits. Balances are recalculated whenever a split is added or
+ * removed from an account, so YMMV on whether this should be set.
+ *
+ * @param check_txn_splits If the pointers are not equal, but
+ * everything else so far is equal (including memo, amount, value,
+ * kvp_frame), then, when comparing the parenting transactions with
+ * xaccTransEqual(), set its argument check_splits to be TRUE.
+ */
+gboolean xaccSplitEqual(const Split *sa, const Split *sb,
+ gboolean check_guids,
+ gboolean check_balances,
+ gboolean check_txn_splits);
+
+/** The xaccSplitLookup() subroutine will return the
+ * split associated with the given id, or NULL
+ * if there is no such split. */
+Split * xaccSplitLookup (const GUID *guid, QofBook *book);
+#define xaccSplitLookupDirect(g,b) xaccSplitLookup(&(g),b)
+
+
+/**
+ * The xaccSplitGetOtherSplit() is a convenience routine that returns
+ * the other of a pair of splits. If there are more than two
+ * splits, it returns NULL.
+ */
+Split * xaccSplitGetOtherSplit (const Split *split);
+
+/** The xaccIsPeerSplit() is a convenience routine that returns TRUE
+ * (a non-zero value) if the two splits share a common parent
+ * transaction, else it returns FALSE (zero).
+ */
+gboolean xaccIsPeerSplit (const Split *split_1, const Split *split_2);
+
+/** Returns the split type, which is either the string "normal", or
+ * "stock-split" for a split from a stock split (pun intended? :-). */
+const char *xaccSplitGetType(const Split *s);
+
+/** Mark a split to be of type stock split - after this, you shouldn't
+ modify the value anymore, just the amount. */
+void xaccSplitMakeStockSplit(Split *s);
+
+/**
+ * The xaccSplitDateOrder(sa,sb) method is useful for sorting.
+ * if sa and sb have different transactions, return their xaccTransOrder
+ * return a negative value if split sa has a smaller currency-value than sb,
+ * return a positive value if split sa has a larger currency-value than sb,
+ * return a negative value if split sa has a smaller share-price than sb,
+ * return a positive value if split sa has a larger share-price than sb,
+ * then compares memo and action using the strcmp()
+ * c-library routine, returning what strcmp would return.
+ * Then it compares the reconciled flags, then the reconciled dates,
+ * Finally, it returns zero if all of the above match.
+ */
+int xaccSplitDateOrder (const Split *sa, const Split *sb);
+
+
+/*
+ * These functions compare two splits by different criteria.
+ *
+ * These functions were added because converting strings to guile
+ * for comparisons in the transaction report is terribly inefficient.
+ * More may be added here in future if it turns out that other types
+ * of comparisons also induces guile slowdowns.
+ */
+
+/** Compare two splits by full name of account. Returns similar to
+ * strcmp. */
+int xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb);
+/** Compare two splits by code of account. Returns similar to
+ * strcmp. */
+int xaccSplitCompareAccountCodes(const Split *sa, const Split *sb);
+/** Compare two splits by full name of the other account. Returns
+ * similar to strcmp. This function attempts to find the split on the
+ * other side of a transaction and compare on it. */
+int xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb);
+/** Compare two splits by code of the other account. Returns similar
+ * to strcmp. This function attempts to find the split on the
+ * other side of a transaction and compare on it. */
+int xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb);
+
+
+/**
+ * These functions take a split, get the corresponding split on the
+ * "other side" of the transaction, and extract either the name or code
+ * of that split, reverting to returning a constant "Split" if the
+ * transaction has more than one split on the "other side". These
+ * were added for the transaction report, and is in C because the code
+ * was already written in C for the above functions and duplication
+ * is silly.
+ */
+
+char * xaccSplitGetCorrAccountFullName(const Split *sa, char seperator);
+/** document me */
+const char * xaccSplitGetCorrAccountName(const Split *sa);
+/** document me */
+const char * xaccSplitGetCorrAccountCode(const Split *sa);
+
+/** @} */
+
+
+
+/** @name Split deprecated functions
+@{
+*/
+
+/** @deprecated The xaccSplitSetSharePrice() method sets the price of the
+ * split. DEPRECATED - set the value and amount instead. */
+void xaccSplitSetSharePrice (Split *split, gnc_numeric price);
+
+/** @} */
+
+
+/********************************************************************\
+ * Miscellaneous utility routines.
+\********************************************************************/
+
+
+/** @name Split voiding
+@{
+*/
+
+/** Returns the original pre-void amount of a split.
+ *
+ * @param split The split in question.
+ *
+ * @return A gnc_numeric containing the original value of this split.
+ * Returns a gnc_numeric of zero upon error.
+ */
+gnc_numeric xaccSplitVoidFormerAmount(const Split *split);
+
+/** Returns the original pre-void value of a split.
+ *
+ * @param split The split in question.
+ *
+ * @return A gnc_numeric containing the original amount of this split.
+ * Returns a gnc_numeric of zero upon error.
+ */
+gnc_numeric xaccSplitVoidFormerValue(const Split *split);
+
+/** @} */
+
+/** @name Split Parameter names
+
+ * Note, if you want to get the equivalent of "ACCT_MATCH_ALL" you
+ * need to create a search on the following parameter list:
+ * SPLIT->SPLIT_TRANS->TRANS_SPLITLIST->SPLIT_ACCOUNT_GUID. If you do
+ * this, you might want to use the ACCOUNT_MATCH_ALL_TYPE as the
+ * override so the gnome-search dialog displays the right type.
+ @{
+*/
+#define SPLIT_KVP "kvp"
+
+#define SPLIT_DATE_RECONCILED "date-reconciled"
+#define SPLIT_BALANCE "balance"
+#define SPLIT_CLEARED_BALANCE "cleared-balance"
+#define SPLIT_RECONCILED_BALANCE "reconciled-balance"
+#define SPLIT_MEMO "memo"
+#define SPLIT_ACTION "action"
+#define SPLIT_RECONCILE "reconcile-flag"
+#define SPLIT_AMOUNT "amount"
+#define SPLIT_SHARE_PRICE "share-price"
+#define SPLIT_VALUE "value"
+#define SPLIT_TYPE "type"
+#define SPLIT_VOIDED_AMOUNT "voided-amount"
+#define SPLIT_VOIDED_VALUE "voided-value"
+#define SPLIT_LOT "lot"
+#define SPLIT_TRANS "trans"
+#define SPLIT_ACCOUNT "account"
+#define SPLIT_ACCOUNT_GUID "account-guid" /**< for guid_match_all */
+/* used for SORTING ONLY */
+#define SPLIT_ACCT_FULLNAME "acct-fullname"
+#define SPLIT_CORR_ACCT_NAME "corr-acct-fullname"
+#define SPLIT_CORR_ACCT_CODE "corr-acct-code"
+/** @} */
+
+/** \deprecated */
+#define xaccSplitGetGUID(X) qof_entity_get_guid(QOF_ENTITY(X))
+/** \deprecated */
+#define xaccSplitReturnGUID(X) (X ? *(qof_entity_get_guid(QOF_ENTITY(X))) : *(guid_null()))
+
+#endif /* XACC_SPLIT_H */
+/** @} */
+/** @} */
Copied: gnucash/trunk/src/engine/SplitP.h (from rev 13359, gnucash/trunk/src/engine/TransactionP.h)
===================================================================
--- gnucash/trunk/src/engine/TransactionP.h 2006-02-22 06:01:07 UTC (rev 13359)
+++ gnucash/trunk/src/engine/SplitP.h 2006-02-22 21:52:46 UTC (rev 13363)
@@ -0,0 +1,243 @@
+/********************************************************************\
+ * SplitP.h -- private header for splits *
+ * Copyright (C) 1997 Robin D. Clark *
+ * Copyright (C) 1997-2000 Linas Vepstas <linas at linas.org> *
+ * Copyright (C) 2000 Bill Gribble *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+
+/*
+ * FILE:
+ * SplitP.h
+ *
+ * FUNCTION:
+ * The is the *private* split header file. Code outside of
+ * engine should *not* include this file. This is because code
+ * outside of the engine should *never* access any of the structure
+ * members directly.
+ *
+ * Note that this header file also defines prototypes for various
+ * routines that perform sub-atomic updates of the accounting
+ * structures. If these routines are not used properly, they
+ * can result in inconsistent, unbalanced accounting structures.
+ * In other words, their use is dangerous, and their use outside
+ * of the scope of the engine is forbidden.
+ *
+ */
+
+#ifndef XACC_SPLIT_P_H
+#define XACC_SPLIT_P_H
+
+#include "config.h"
+
+#include <time.h>
+#include <glib.h>
+
+#include "gnc-engine.h" /* for typedefs */
+#include "qof.h"
+
+
+/** STRUCTS *********************************************************/
+/* A "split" is more commonly referred to as an "entry" in a "transaction".
+ */
+
+/* Flags for handling cap-gains status */
+#define GAINS_STATUS_UNKNOWN 0xff
+#define GAINS_STATUS_CLEAN 0x0
+#define GAINS_STATUS_GAINS 0x3
+#define GAINS_STATUS_DATE_DIRTY 0x10
+#define GAINS_STATUS_AMNT_DIRTY 0x20
+#define GAINS_STATUS_VALU_DIRTY 0x40
+#define GAINS_STATUS_LOT_DIRTY 0x80
+#define GAINS_STATUS_ADIRTY (GAINS_STATUS_AMNT_DIRTY|GAINS_STATUS_LOT_DIRTY)
+#define GAINS_STATUS_VDIRTY (GAINS_STATUS_VALU_DIRTY)
+#define GAINS_STATUS_A_VDIRTY (GAINS_STATUS_AMNT_DIRTY|GAINS_STATUS_VALU_DIRTY|GAINS_STATUS_LOT_DIRTY)
+
+struct split_s
+{
+ QofInstance inst;
+
+ Account *acc; /* back-pointer to debited/credited account */
+
+ GNCLot *lot; /* back-pointer to debited/credited lot */
+
+ Transaction *parent; /* parent of split */
+
+ /* The memo field is an arbitrary user-assiged value.
+ * It is intended to hold a short (zero to forty character) string
+ * that is displayed by the GUI along with this split.
+ */
+ char * memo;
+
+ /* The action field is an arbitrary user-assigned value.
+ * It is meant to be a very short (one to ten character) string that
+ * signifies the "type" of this split, such as e.g. Buy, Sell, Div,
+ * Withdraw, Deposit, ATM, Check, etc. The idea is that this field
+ * can be used to create custom reports or graphs of data.
+ */
+ char * action; /* Buy, Sell, Div, etc. */
+
+ Timespec date_reconciled; /* date split was reconciled */
+ char reconciled; /* The reconciled field */
+
+ /* gains is a flag used to track the relationship between
+ * capital-gains splits. Depending on its value, this flag indicates
+ * if this split is the source of gains, if this split is a record
+ * of the gains, and if values are 'dirty' and need to be recomputed.
+ */
+ unsigned char gains;
+
+ /* 'gains_split' is a convenience pointer used to track down the
+ * other end of a cap-gains transaction pair. NULL if this split
+ * doesn't involve cap gains.
+ */
+ Split *gains_split;
+
+ /* 'value' is the quantity of the transaction balancing commodity
+ * (i.e. currency) involved, 'amount' is the amount of the account's
+ * commodity involved. */
+ gnc_numeric value;
+ gnc_numeric amount;
+
+ /* -------------------------------------------------------------- */
+ /* Below follow some 'temporary' fields */
+
+ /* The various "balances" are the sum of all of the values of
+ * all the splits in the account, up to and including this split.
+ * These balances apply to a sorting order by date posted
+ * (not by date entered). */
+ gnc_numeric balance;
+ gnc_numeric cleared_balance;
+ gnc_numeric reconciled_balance;
+
+ /* -------------------------------------------------------------- */
+ /* Backend private expansion data */
+ guint32 idata; /* used by the sql backend for kvp management */
+};
+
+
+/* Set the split's GUID. This should only be done when reading
+ * a split from a datafile, or some other external source. Never
+ * call this on an existing split! */
+#define xaccSplitSetGUID(s,g) qof_entity_set_guid(QOF_ENTITY(s),g)
+
+/* The xaccFreeSplit() method simply frees all memory associated
+ * with the split. It does not verify that the split isn't
+ * referenced in some account. If the split is referenced by an
+ * account, then calling this method will leave the system in an
+ * inconsistent state. This *will* lead to crashes and hangs.
+ */
+void xaccFreeSplit (Split *split); /* frees memory */
+
+Split * xaccSplitClone (const Split *s);
+
+Split *xaccDupeSplit (const Split *s);
+G_INLINE_FUNC void mark_split (Split *s);
+G_INLINE_FUNC void gen_event (const Split *split);
+
+void xaccSplitVoid(Split *split);
+void xaccSplitUnvoid(Split *split);
+
+/* Compute the value of a list of splits in the given currency,
+ * excluding the skip_me split. */
+gnc_numeric xaccSplitsComputeValue (GList *splits, Split * skip_me,
+ const gnc_commodity * base_currency);
+
+/* Code to register Split type with the engine */
+gboolean xaccSplitRegister (void);
+
+/* The xaccSplitDetermineGainStatus() routine will analyze the
+ * the split, and try to set the internal status flags
+ * appropriately for the split. These flags indicate if the split
+ * represents cap gains, and if the gains value/amount needs to be
+ * recomputed.
+ */
+void xaccSplitDetermineGainStatus (Split *split);
+
+/* ---------------------------------------------------------------- */
+/* Deprecated routines */
+void DxaccSplitSetSharePriceAndAmount (Split *split,
+ double price,
+ double amount);
+void DxaccSplitSetShareAmount (Split *split, double amount);
+
+/********************************************************************\
+ * sorting comparison function
+ *
+ * returns a negative value if transaction a is dated earlier than b,
+ * returns a positive value if transaction a is dated later than b,
+ *
+ * This function tries very hard to uniquely order all transactions.
+ * If two transactions occur on the same date, then their "num" fields
+ * are compared. If the num fields are identical, then the description
+ * fields are compared. If these are identical, then the memo fields
+ * are compared. Hopefully, there will not be any transactions that
+ * occur on the same day that have all three of these values identical.
+ *
+ * Note that being able to establish this kind of absolute order is
+ * important for some of the ledger display functions.
+ *
+ * Yes, this kind of code dependency is ugly, but the alternatives seem
+ * ugly too.
+ *
+\********************************************************************/
+
+
+#define DATE_CMP(aaa,bbb,field) { \
+ /* if dates differ, return */ \
+ if ( (aaa->field.tv_sec) < \
+ (bbb->field.tv_sec)) { \
+ return -1; \
+ } else \
+ if ( (aaa->field.tv_sec) > \
+ (bbb->field.tv_sec)) { \
+ return +1; \
+ } \
+ \
+ /* else, seconds match. check nanoseconds */ \
+ if ( (aaa->field.tv_nsec) < \
+ (bbb->field.tv_nsec)) { \
+ return -1; \
+ } else \
+ if ( (aaa->field.tv_nsec) > \
+ (bbb->field.tv_nsec)) { \
+ return +1; \
+ } \
+}
+
+#define CHECK_GAINS_STATUS(s) \
+ if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus(s);
+
+#define SET_GAINS_DIRTY(s,flg) do { \
+ if (FALSE == (GAINS_STATUS_GAINS & s->gains)) { \
+ s->gains |= flg; \
+ } else { \
+ if (s->gains_split) s->gains_split->gains |= flg; \
+ } \
+} while (0)
+
+#define SET_GAINS_ADIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_ADIRTY);
+#define SET_GAINS_A_VDIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_A_VDIRTY);
+#define SET_GAINS_VDIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_VDIRTY);
+
+/*@}*/
+
+
+#endif /* XACC_SPLIT_P_H */
Modified: gnucash/trunk/src/engine/Transaction.c
===================================================================
--- gnucash/trunk/src/engine/Transaction.c 2006-02-22 17:41:58 UTC (rev 13362)
+++ gnucash/trunk/src/engine/Transaction.c 2006-02-22 21:52:46 UTC (rev 13363)
@@ -1,5 +1,5 @@
/********************************************************************\
- * Transaction.c -- transaction & split implementation *
+ * Transaction.c -- transaction implementation *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1997-2003 Linas Vepstas <linas at linas.org> *
* Copyright (C) 2000 Bill Gribble <grib at billgribble.com> *
@@ -39,6 +39,7 @@
#include "Scrub.h"
#include "Scrub3.h"
#include "TransactionP.h"
+#include "SplitP.h"
#include "TransLog.h"
#include "cap-gains.h"
#include "gnc-commodity.h"
@@ -63,8 +64,6 @@
const char *trans_notes_str = "notes";
const char *void_reason_str = "void-reason";
const char *void_time_str = "void-time";
-const char *void_former_amt_str = "void-former-amount";
-const char *void_former_val_str = "void-former-value";
const char *void_former_notes_str = "void-former-notes";
/* KVP entry for date-due value */
@@ -72,14 +71,11 @@
#define TRANS_TXN_TYPE_KVP "trans-txn-type"
#define TRANS_READ_ONLY_REASON "trans-read-only"
-#define PRICE_SIGFIGS 6
-
#define ISO_DATELENGTH 32 /* length of an iso 8601 date string. */
/* This static indicates the debugging module that this .o belongs to. */
static QofLogModule log_module = GNC_MOD_ENGINE;
-G_INLINE_FUNC void check_open (const Transaction *trans);
void check_open (const Transaction *trans)
{
if (trans && 0 >= trans->inst.editlevel)
@@ -87,489 +83,8 @@
}
/********************************************************************\
- * xaccInitSplit
- * Initialize a Split structure
\********************************************************************/
-static void
-xaccInitSplit(Split * split, QofBook *book)
-{
- /* fill in some sane defaults */
- split->acc = NULL;
- split->parent = NULL;
- split->lot = NULL;
-
- split->action = gnc_string_cache_insert("");
- split->memo = gnc_string_cache_insert("");
- split->reconciled = NREC;
- split->amount = gnc_numeric_zero();
- split->value = gnc_numeric_zero();
-
- split->date_reconciled.tv_sec = 0;
- split->date_reconciled.tv_nsec = 0;
-
- split->balance = gnc_numeric_zero();
- split->cleared_balance = gnc_numeric_zero();
- split->reconciled_balance = gnc_numeric_zero();
-
- split->idata = 0;
-
- split->gains = GAINS_STATUS_UNKNOWN;
- split->gains_split = NULL;
-
- qof_instance_init(&split->inst, GNC_ID_SPLIT, book);
-}
-
-void
-xaccSplitReinit(Split * split)
-{
- /* fill in some sane defaults */
- split->acc = NULL;
- split->parent = NULL;
- split->lot = NULL;
-
- CACHE_REPLACE(split->action, "");
- CACHE_REPLACE(split->memo, "");
- split->reconciled = NREC;
- split->amount = gnc_numeric_zero();
- split->value = gnc_numeric_zero();
-
- split->date_reconciled.tv_sec = 0;
- split->date_reconciled.tv_nsec = 0;
-
- split->balance = gnc_numeric_zero();
- split->cleared_balance = gnc_numeric_zero();
- split->reconciled_balance = gnc_numeric_zero();
-
- if (split->inst.kvp_data)
- kvp_frame_delete(split->inst.kvp_data);
- split->inst.kvp_data = kvp_frame_new();
- split->idata = 0;
-
- split->gains = GAINS_STATUS_UNKNOWN;
- split->gains_split = NULL;
-}
-
-/********************************************************************\
-\********************************************************************/
-
-Split *
-xaccMallocSplit(QofBook *book)
-{
- Split *split;
- g_return_val_if_fail (book, NULL);
-
- split = g_new0 (Split, 1);
- xaccInitSplit (split, book);
-
- return split;
-}
-
-/********************************************************************\
-\********************************************************************/
-/* This routine is not exposed externally, since it does weird things,
- * like not really setting up the parent account correctly, and ditto
- * the parent transaction. This routine is prone to programmer error
- * if not used correctly. It is used only by the edit-rollback code.
- * Don't get duped!
- */
-
-static Split *
-xaccDupeSplit (const Split *s)
-{
- Split *split = g_new0 (Split, 1);
-
- /* Trash the guid and entity table. We don't want to mistake
- * the cloned splits as something official. If we ever use this
- * split, we'll have to fix this up.
- */
- split->inst.entity.e_type = NULL;
- split->inst.entity.guid = *guid_null();
- split->inst.entity.collection = NULL;
- split->inst.book = s->inst.book;
-
- split->parent = s->parent;
- split->acc = s->acc;
- split->lot = s->lot;
-
- split->memo = gnc_string_cache_insert(s->memo);
- split->action = gnc_string_cache_insert(s->action);
-
- split->inst.kvp_data = kvp_frame_copy (s->inst.kvp_data);
-
- split->reconciled = s->reconciled;
- split->date_reconciled = s->date_reconciled;
-
- split->value = s->value;
- split->amount = s->amount;
-
- /* no need to futz with the balances; these get wiped each time ...
- * split->balance = s->balance;
- * split->cleared_balance = s->cleared_balance;
- * split->reconciled_balance = s->reconciled_balance;
- */
-
- return split;
-}
-
-Split *
-xaccSplitClone (const Split *s)
-{
- Split *split = g_new0 (Split, 1);
-
- split->parent = NULL;
- split->memo = gnc_string_cache_insert(s->memo);
- split->action = gnc_string_cache_insert(s->action);
- split->reconciled = s->reconciled;
- split->date_reconciled = s->date_reconciled;
- split->value = s->value;
- split->amount = s->amount;
- split->balance = s->balance;
- split->cleared_balance = s->cleared_balance;
- split->reconciled_balance = s->reconciled_balance;
- split->idata = 0;
-
- split->gains = GAINS_STATUS_UNKNOWN;
- split->gains_split = NULL;
-
- qof_instance_init(&split->inst, GNC_ID_SPLIT, s->inst.book);
- kvp_frame_delete(split->inst.kvp_data);
- split->inst.kvp_data = kvp_frame_copy(s->inst.kvp_data);
-
- xaccAccountInsertSplit(s->acc, split);
- if (s->lot)
- {
- /* FIXME: Doesn't look right. */
- s->lot->splits = g_list_append (s->lot->splits, split);
- s->lot->is_closed = -1;
- }
- return split;
-}
-
-#ifdef DUMP_FUNCTIONS
-static void
-xaccSplitDump (const Split *split, const char *tag)
-{
- printf(" %s Split %p", tag, split);
- printf(" GUID: %s\n", guid_to_string(&split->guid));
- printf(" Book: %p\n", split->inst.book);
- printf(" Account: %p\n", split->acc);
- printf(" Lot: %p\n", split->lot);
- printf(" Parent: %p\n", split->parent);
- printf(" Memo: %s\n", split->memo ? split->memo : "(null)");
- printf(" Action: %s\n", split->action ? split->action : "(null)");
- printf(" KVP Data: %p\n", split->inst.kvp_data);
- printf(" Recncld: %c (date %s)\n", split->reconciled,
- gnc_print_date(split->date_reconciled));
- printf(" Value: %s\n", gnc_numeric_to_string(split->value));
- printf(" Amount: %s\n", gnc_numeric_to_string(split->amount));
- printf(" Balance: %s\n", gnc_numeric_to_string(split->balance));
- printf(" CBalance: %s\n", gnc_numeric_to_string(split->cleared_balance));
- printf(" RBalance: %s\n",
- gnc_numeric_to_string(split->reconciled_balance));
- printf(" idata: %x\n", split->idata);
-}
-#endif
-
-/********************************************************************\
-\********************************************************************/
-
-void
-xaccFreeSplit (Split *split)
-{
- if (!split) return;
-
- /* Debug double-free's */
- if (((char *) 1) == split->memo)
- {
- PERR ("double-free %p", split);
- return;
- }
- gnc_string_cache_remove(split->memo);
- gnc_string_cache_remove(split->action);
-
- /* Just in case someone looks up freed memory ... */
- split->memo = (char *) 1;
- split->action = NULL;
- split->reconciled = NREC;
- split->amount = gnc_numeric_zero();
- split->value = gnc_numeric_zero();
- split->parent = NULL;
- split->lot = NULL;
- split->acc = NULL;
-
- split->date_reconciled.tv_sec = 0;
- split->date_reconciled.tv_nsec = 0;
-
- // Is this right?
- if (split->gains_split) split->gains_split->gains_split = NULL;
- qof_instance_release(&split->inst);
- g_free(split);
-}
-
-/*
- * Helper routine for xaccSplitEqual.
- */
-static gboolean
-xaccSplitEqualCheckBal (const char *tag, gnc_numeric a, gnc_numeric b)
-{
- char *str_a, *str_b;
-
- if (gnc_numeric_equal (a, b))
- return TRUE;
-
- str_a = gnc_numeric_to_string (a);
- str_b = gnc_numeric_to_string (b);
-
- PWARN ("%sbalances differ: %s vs %s", tag, str_a, str_b);
-
- g_free (str_a);
- g_free (str_b);
-
- return FALSE;
-}
-
-/********************************************************************
- * xaccSplitEqual
- ********************************************************************/
-gboolean
-xaccSplitEqual(const Split *sa, const Split *sb,
- gboolean check_guids,
- gboolean check_balances,
- gboolean check_txn_splits)
-{
- if (!sa && !sb) return TRUE; /* Arguable. FALSE is better, methinks */
-
- if (!sa || !sb)
- {
- PWARN ("one is NULL");
- return FALSE;
- }
-
- if (sa == sb) return TRUE;
-
- if (check_guids) {
- if (!guid_equal(&(sa->inst.entity.guid), &(sb->inst.entity.guid)))
- {
- PWARN ("GUIDs differ");
- return FALSE;
- }
- }
-
- /* Since these strings are cached we can just use pointer equality */
- if (sa->memo != sb->memo)
- {
- PWARN ("memos differ: (%p)%s vs (%p)%s",
- sa->memo, sa->memo, sb->memo, sb->memo);
- return FALSE;
- }
-
- if (sa->action != sb->action)
- {
- PWARN ("actions differ: %s vs %s", sa->action, sb->action);
- return FALSE;
- }
-
- if (kvp_frame_compare(sa->inst.kvp_data, sb->inst.kvp_data) != 0)
- {
- char *frame_a;
- char *frame_b;
-
- frame_a = kvp_frame_to_string (sa->inst.kvp_data);
- frame_b = kvp_frame_to_string (sb->inst.kvp_data);
-
- PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
-
- g_free (frame_a);
- g_free (frame_b);
-
- return FALSE;
- }
-
- if (sa->reconciled != sb->reconciled)
- {
- PWARN ("reconcile flags differ: %c vs %c", sa->reconciled, sb->reconciled);
- return FALSE;
- }
-
- if (timespec_cmp(&(sa->date_reconciled), &(sb->date_reconciled)))
- {
- PWARN ("reconciled date differs");
- return FALSE;
- }
-
- if (!gnc_numeric_eq(xaccSplitGetAmount (sa), xaccSplitGetAmount (sb)))
- {
- char *str_a;
- char *str_b;
-
- str_a = gnc_numeric_to_string (xaccSplitGetAmount (sa));
- str_b = gnc_numeric_to_string (xaccSplitGetAmount (sb));
-
- PWARN ("amounts differ: %s vs %s", str_a, str_b);
-
- g_free (str_a);
- g_free (str_b);
-
- return FALSE;
- }
-
- if (!gnc_numeric_eq(xaccSplitGetValue (sa), xaccSplitGetValue (sb)))
- {
- char *str_a;
- char *str_b;
-
- str_a = gnc_numeric_to_string (xaccSplitGetValue (sa));
- str_b = gnc_numeric_to_string (xaccSplitGetValue (sb));
-
- PWARN ("values differ: %s vs %s", str_a, str_b);
-
- g_free (str_a);
- g_free (str_b);
-
- return FALSE;
- }
-
- if (check_balances) {
- if (!xaccSplitEqualCheckBal ("", sa->balance, sb->balance))
- return FALSE;
- if (!xaccSplitEqualCheckBal ("cleared ", sa->cleared_balance,
- sb->cleared_balance))
- return FALSE;
- if (!xaccSplitEqualCheckBal ("reconciled ", sa->reconciled_balance,
- sb->reconciled_balance))
- return FALSE;
- }
-
- if (!xaccTransEqual(sa->parent, sb->parent, check_guids, check_txn_splits,
- check_balances, FALSE))
- {
- PWARN ("transactions differ");
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-add_keys_to_list(gpointer key, gpointer val, gpointer list)
-{
- *(GList **)list = g_list_prepend(*(GList **)list, key);
-}
-
-GList *
-xaccSplitListGetUniqueTransactions(const GList *splits)
-{
- const GList *node;
- GList *transList = NULL;
- GHashTable *transHash = g_hash_table_new(g_direct_hash, g_direct_equal);
-
- for(node = splits; node; node = node->next) {
- Transaction *trans = xaccSplitGetParent((Split *)(node->data));
- g_hash_table_insert(transHash, trans, trans);
- }
- g_hash_table_foreach(transHash, add_keys_to_list, &transList);
- g_hash_table_destroy(transHash);
- return transList;
-}
-
-/********************************************************************
- * Account funcs
- ********************************************************************/
-
-Account *
-xaccSplitGetAccount (const Split *s)
-{
- return s ? s->acc : NULL;
-}
-
-/********************************************************************\
-\********************************************************************/
-
-Split *
-xaccSplitLookup (const GUID *guid, QofBook *book)
-{
- QofCollection *col;
- if (!guid || !book) return NULL;
- col = qof_book_get_collection (book, GNC_ID_SPLIT);
- return (Split *) qof_collection_lookup_entity (col, guid);
-}
-
-/********************************************************************\
-\********************************************************************/
-/* Routines for marking splits dirty, and for sending out change
- * events. Note that we can't just mark-n-generate-event in one
- * step, since sometimes we need to mark things up before its suitable
- * to send out a change event.
- */
-
-/* CHECKME: This function modifies the Split without dirtying or
- checking its parent. Is that correct? */
-void
-xaccSplitDetermineGainStatus (Split *split)
-{
- Split *other;
- KvpValue *val;
-
- if (GAINS_STATUS_UNKNOWN != split->gains) return;
-
- other = xaccSplitGetCapGainsSplit (split);
- if (other)
- {
- split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
- split->gains_split = other;
- return;
- }
-
- val = kvp_frame_get_slot (split->inst.kvp_data, "gains-source");
- if (!val)
- {
- // FIXME: This looks bogus.
- other = xaccSplitGetOtherSplit (split);
- if (other)
- val = kvp_frame_get_slot (other->inst.kvp_data, "gains-source");
- split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
- } else {
- QofCollection *col;
- col = qof_book_get_collection (split->inst.book, GNC_ID_SPLIT);
- split->gains = GAINS_STATUS_GAINS;
- other = (Split *) qof_collection_lookup_entity (col,
- kvp_value_get_guid (val));
- split->gains_split = other;
- }
-}
-
-#define CHECK_GAINS_STATUS(s) \
- if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus(s);
-
-#define SET_GAINS_DIRTY(s,flg) do { \
- if (FALSE == (GAINS_STATUS_GAINS & s->gains)) { \
- s->gains |= flg; \
- } else { \
- if (s->gains_split) s->gains_split->gains |= flg; \
- } \
-} while (0)
-
-#define SET_GAINS_ADIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_ADIRTY);
-#define SET_GAINS_A_VDIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_A_VDIRTY);
-#define SET_GAINS_VDIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_VDIRTY);
-
-G_INLINE_FUNC void mark_split (Split *s);
-void mark_split (Split *s)
-{
- Account *account = s->acc;
-
- if (account && !account->inst.do_free)
- {
- account->balance_dirty = TRUE;
- account->sort_dirty = TRUE;
- }
-
- /* set dirty flag on lot too. */
- if (s->lot) s->lot->is_closed = -1;
-}
-
-
G_INLINE_FUNC void mark_trans (Transaction *trans);
void mark_trans (Transaction *trans)
{
@@ -581,31 +96,6 @@
}
}
-G_INLINE_FUNC void gen_event (const Split *split);
-void gen_event (const Split *split)
-{
- Account *account = split->acc;
- Transaction *trans = split->parent;
- GNCLot *lot = split->lot;
-
- if (account)
- {
- xaccGroupMarkNotSaved (account->parent);
- gnc_engine_gen_event (&account->inst.entity, GNC_EVENT_MODIFY);
- }
-
- if (trans)
- {
- gnc_engine_gen_event (&trans->inst.entity, GNC_EVENT_MODIFY);
- }
-
- if (lot)
- {
- /* A change of value/amnt affects gains displat, etc. */
- gnc_engine_gen_event (&lot->inst.entity, GNC_EVENT_MODIFY);
- }
-}
-
G_INLINE_FUNC void gen_event_trans (Transaction *trans);
void gen_event_trans (Transaction *trans)
{
@@ -632,235 +122,6 @@
}
/********************************************************************\
-\********************************************************************/
-
-static inline int
-get_currency_denom(const Split * s)
-{
- if (!s)
- {
- return 0;
- }
- else if(!s->parent || !s->parent->common_currency)
- {
- return 100000;
- }
- else
- {
- return gnc_commodity_get_fraction (s->parent->common_currency);
- }
-}
-
-static inline int
-get_commodity_denom(const Split * s)
-{
- if (!s)
- {
- return 0;
- }
- else if (!s->acc)
- {
- return 100000;
- }
- else
- {
- return xaccAccountGetCommoditySCU(s->acc);
- }
-}
-
-/********************************************************************
- * xaccSplitGetSlots
- ********************************************************************/
-
-KvpFrame *
-xaccSplitGetSlots (const Split * s)
-{
- return qof_instance_get_slots(QOF_INSTANCE(s));
-}
-
-void
-xaccSplitSetSlots_nc(Split *s, KvpFrame *frm)
-{
- if (!s || !frm) return;
- check_open (s->parent);
-
- qof_instance_set_slots(QOF_INSTANCE(s), frm);
-}
-
-/********************************************************************\
-\********************************************************************/
-
-void
-DxaccSplitSetSharePriceAndAmount (Split *s, double price, double amt)
-{
- if (!s) return;
- ENTER (" ");
- check_open (s->parent);
-
- s->amount = double_to_gnc_numeric(amt, get_commodity_denom(s),
- GNC_HOW_RND_ROUND);
- s->value = double_to_gnc_numeric(price * amt, get_currency_denom(s),
- GNC_HOW_RND_ROUND);
-
- SET_GAINS_A_VDIRTY(s);
- mark_split (s);
-}
-
-void
-xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)
-{
- if (!s) return;
- ENTER (" ");
- check_open (s->parent);
-
- s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
- GNC_HOW_RND_ROUND);
- s->value = gnc_numeric_mul(s->amount, price,
- get_currency_denom(s), GNC_HOW_RND_ROUND);
-
- SET_GAINS_A_VDIRTY(s);
- mark_split (s);
-}
-
-static void
-qofSplitSetSharePrice (Split *split, gnc_numeric price)
-{
- g_return_if_fail(split);
- split->value = gnc_numeric_mul(xaccSplitGetAmount(split),
- price, get_currency_denom(split),
- GNC_HOW_RND_ROUND);
-}
-
-void
-xaccSplitSetSharePrice (Split *s, gnc_numeric price)
-{
- if (!s) return;
- ENTER (" ");
- check_open (s->parent);
-
- s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
- price, get_currency_denom(s),
- GNC_HOW_RND_ROUND);
-
- SET_GAINS_VDIRTY(s);
- mark_split (s);
-}
-
-void
-DxaccSplitSetShareAmount (Split *s, double damt)
-{
- gnc_numeric old_price, old_amt;
- int commodity_denom = get_commodity_denom(s);
- gnc_numeric amt = double_to_gnc_numeric(damt, commodity_denom,
- GNC_HOW_RND_ROUND);
- if (!s) return;
- ENTER (" ");
- check_open (s->parent);
-
- old_amt = xaccSplitGetAmount (s);
- if (!gnc_numeric_zero_p(old_amt))
- {
- old_price = gnc_numeric_div(xaccSplitGetValue (s),
- old_amt, GNC_DENOM_AUTO,
- GNC_HOW_DENOM_REDUCE);
- }
- else {
- old_price = gnc_numeric_create(1, 1);
- }
-
- s->amount = gnc_numeric_convert(amt, commodity_denom,
- GNC_HOW_RND_NEVER);
- s->value = gnc_numeric_mul(s->amount, old_price,
- get_currency_denom(s), GNC_HOW_RND_ROUND);
-
- SET_GAINS_A_VDIRTY(s);
- mark_split (s);
-}
-
-static void
-qofSplitSetAmount (Split *split, gnc_numeric amt)
-{
- g_return_if_fail(split);
- if (split->acc)
- {
- split->amount = gnc_numeric_convert(amt,
- get_commodity_denom(split), GNC_HOW_RND_ROUND);
- }
- else { split->amount = amt; }
-}
-
-/* The amount of the split in the _account's_ commodity. */
-void
-xaccSplitSetAmount (Split *s, gnc_numeric amt)
-{
- if (!s) return;
- g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
- ENTER ("(split=%p) old amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
- " new amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
- s->amount.num, s->amount.denom, amt.num, amt.denom);
-
- check_open (s->parent);
- if (s->acc)
- s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
- GNC_HOW_RND_ROUND);
- else
- s->amount = amt;
-
- SET_GAINS_ADIRTY(s);
- mark_split (s);
- LEAVE("");
-}
-
-static void
-qofSplitSetValue (Split *split, gnc_numeric amt)
-{
- g_return_if_fail(split);
- split->value = gnc_numeric_convert(amt,
- get_currency_denom(split), GNC_HOW_RND_ROUND);
-}
-
-/* The value of the split in the _transaction's_ currency. */
-void
-xaccSplitSetValue (Split *s, gnc_numeric amt)
-{
- if (!s) return;
-
- g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
- ENTER ("(split=%p) old val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
- " new val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
- s->value.num, s->value.denom, amt.num, amt.denom);
-
- check_open (s->parent);
- s->value = gnc_numeric_convert(amt, get_currency_denom(s),
- GNC_HOW_RND_ROUND);
-
- SET_GAINS_VDIRTY(s);
- mark_split (s);
- LEAVE ("");
-}
-
-/********************************************************************\
-\********************************************************************/
-
-gnc_numeric
-xaccSplitGetBalance (const Split *s)
-{
- return s ? s->balance : gnc_numeric_zero();
-}
-
-gnc_numeric
-xaccSplitGetClearedBalance (const Split *s)
-{
- return s ? s->cleared_balance : gnc_numeric_zero();
-}
-
-gnc_numeric
-xaccSplitGetReconciledBalance (const Split *s)
-{
- return s ? s->reconciled_balance : gnc_numeric_zero();
-}
-
-/********************************************************************\
* xaccInitTransaction
* Initialize a transaction structure
\********************************************************************/
@@ -1283,141 +544,7 @@
/********************************************************************\
\********************************************************************/
-void
-xaccSplitSetBaseValue (Split *s, gnc_numeric value,
- const gnc_commodity * base_currency)
-{
- const gnc_commodity *currency;
- const gnc_commodity *commodity;
-
- if (!s) return;
- check_open (s->parent);
-
- if (!s->acc)
- {
- PERR ("split must have a parent account");
- return;
- }
-
- currency = xaccTransGetCurrency (s->parent);
- commodity = xaccAccountGetCommodity (s->acc);
-
- /* If the base_currency is the transaction's commodity ('currency'),
- * set the value. If it's the account commodity, set the
- * amount. If both, set both. */
- if (gnc_commodity_equiv(currency, base_currency)) {
- if (gnc_commodity_equiv(commodity, base_currency)) {
- s->amount = gnc_numeric_convert(value,
- get_commodity_denom(s),
- GNC_HOW_RND_NEVER);
- }
- s->value = gnc_numeric_convert(value,
- get_currency_denom(s),
- GNC_HOW_RND_NEVER);
- }
- else if (gnc_commodity_equiv(commodity, base_currency)) {
- s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
- GNC_HOW_RND_NEVER);
- }
- else {
- PERR ("inappropriate base currency %s "
- "given split currency=%s and commodity=%s\n",
- gnc_commodity_get_printname(base_currency),
- gnc_commodity_get_printname(currency),
- gnc_commodity_get_printname(commodity));
- return;
- }
-
- SET_GAINS_A_VDIRTY(s);
- mark_split (s);
-}
-
gnc_numeric
-xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)
-{
- if (!s || !s->acc || !s->parent) return gnc_numeric_zero();
-
- /* be more precise -- the value depends on the currency we want it
- * expressed in. */
- if (gnc_commodity_equiv(xaccTransGetCurrency(s->parent), base_currency))
- return xaccSplitGetValue(s);
- if (gnc_commodity_equiv(xaccAccountGetCommodity(s->acc), base_currency))
- return xaccSplitGetAmount(s);
-
- PERR ("inappropriate base currency %s "
- "given split currency=%s and commodity=%s\n",
- gnc_commodity_get_printname(base_currency),
- gnc_commodity_get_printname(xaccTransGetCurrency (s->parent)),
- gnc_commodity_get_printname(xaccAccountGetCommodity(s->acc)));
- return gnc_numeric_zero();
-}
-
-/********************************************************************\
-\********************************************************************/
-
-gnc_numeric
-xaccSplitsComputeValue (GList *splits, Split * skip_me,
- const gnc_commodity * base_currency)
-{
- GList *node;
- gnc_numeric value = gnc_numeric_zero();
-
- g_return_val_if_fail (base_currency, value);
-
- ENTER (" currency=%s", gnc_commodity_get_mnemonic (base_currency));
-
- for (node = splits; node; node = node->next)
- {
- Split *s = node->data;
- const gnc_commodity *currency;
- const gnc_commodity *commodity;
-
- if (s == skip_me) continue;
-
- /* value = gnc_numeric_add(value, xaccSplitGetBaseValue(s, base_currency),
- GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); */
-
- /* The split-editor often sends us 'temp' splits whose account
- * hasn't yet been set. Be lenient, and assume an implied base
- * currency. If there's a problem later, the scrub routines will
- * pick it up.
- */
- commodity = s->acc ? xaccAccountGetCommodity (s->acc) : base_currency;
- currency = xaccTransGetCurrency (s->parent);
-
-
- if (gnc_commodity_equiv(currency, base_currency))
- {
- value = gnc_numeric_add(value, xaccSplitGetValue(s),
- GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
- }
- else if (gnc_commodity_equiv(commodity, base_currency))
- {
- value = gnc_numeric_add(value, xaccSplitGetAmount(s),
- GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
- }
- else {
- PERR ("inconsistent currencies\n"
- "\tbase = '%s', curr='%s', sec='%s'\n",
- gnc_commodity_get_printname(base_currency),
- gnc_commodity_get_printname(currency),
- gnc_commodity_get_printname(commodity));
- g_return_val_if_fail (FALSE, value);
- }
- }
-
- /* Note that just because the currencies are equivalent
- * doesn't mean the denominators are the same! */
- value = gnc_numeric_convert(value,
- gnc_commodity_get_fraction (base_currency),
- GNC_HOW_RND_ROUND);
-
- LEAVE (" total=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
- value.num, value.denom);
- return value;
-}
-
-gnc_numeric
xaccTransGetImbalance (const Transaction * trans)
{
GList *node;
@@ -1530,54 +657,6 @@
}
gnc_numeric
-xaccSplitConvertAmount (Split *split, Account * account)
-{
- gnc_commodity *acc_com, *to_commodity;
- Transaction *txn;
- gnc_numeric amount, value, convrate;
- Account * split_acc;
-
- amount = xaccSplitGetAmount (split);
-
- /* If this split is attached to this account, OR */
- split_acc = xaccSplitGetAccount (split);
- if (split_acc == account)
- return amount;
-
- /* If split->account->commodity == to_commodity, return the amount */
- acc_com = xaccAccountGetCommodity (split_acc);
- to_commodity = xaccAccountGetCommodity (account);
- if (acc_com && gnc_commodity_equal (acc_com, to_commodity))
- return amount;
-
- /* Ok, this split is not for the viewed account, and the commodity
- * does not match. So we need to do some conversion.
- *
- * First, we can cheat. If this transaction is balanced and has
- * exactly two splits, then we can implicitly determine the exchange
- * rate and just return the 'other' split amount.
- */
- txn = xaccSplitGetParent (split);
- if (txn && gnc_numeric_zero_p (xaccTransGetImbalance (txn))) {
- Split *osplit = xaccSplitGetOtherSplit (split);
-
- if (osplit)
- return gnc_numeric_neg (xaccSplitGetAmount (osplit));
- }
-
- /* ... otherwise, we need to compute the amount from the conversion
- * rate into _this account_. So, find the split into this account,
- * compute the conversion rate (based on amount/value), and then multiply
- * this times the split value.
- */
- convrate = xaccTransGetAccountConvRate(txn, account);
- value = xaccSplitGetValue (split);
- return gnc_numeric_mul (value, convrate,
- gnc_commodity_get_fraction (to_commodity),
- GNC_RND_ROUND);
-}
-
-gnc_numeric
xaccTransGetAccountBalance (const Transaction *trans,
const Account *account)
{
@@ -1919,7 +998,7 @@
* old splits, and insert all of the new splits, but this kind of brute
* forcing will suck memory cycles. So instead we'll try the gentle
* approach first. Note that even in the gentle approach, the
- * CheckDateOrder routine could be cpu-cyle brutal, so it maybe
+ * CheckDateOrder routine could be cpu-cycle brutal, so it maybe
* it could use some tuning.
*/
if (trans->inst.do_free)
@@ -2122,7 +1201,7 @@
* not cause any rebalancing to occur.
\********************************************************************/
-static void
+void
xaccTransRemoveSplit (Transaction *trans, const Split *split)
{
if (trans) {
@@ -2134,54 +1213,6 @@
/********************************************************************\
\********************************************************************/
-gboolean
-xaccSplitDestroy (Split *split)
-{
- Account *acc;
- Transaction *trans;
-
- if (!split) return TRUE;
-
- acc = split->acc;
- trans = split->parent;
- if (acc && !acc->inst.do_free && xaccTransGetReadOnly (trans))
- return FALSE;
-
- check_open (trans);
-
- mark_split (split);
-
- if (trans)
- {
- if (g_list_find(trans->splits, split))
- xaccTransRemoveSplit (trans, split);
- else
- PERR ("split not in transaction");
- }
-
- /* Note: split is removed from lot when it's removed from account */
- xaccAccountRemoveSplit (acc, split);
-
- /* If we're shutting down then destroy the transaction, too, and
- * don't recompute the balance.
- */
- if (qof_book_shutting_down (split->parent->inst.book))
- /* This seems like an odd place to do this. Transactions have
- to be opened to destroy them. */
- xaccTransDestroy (trans);
- else
- /* This seems a bit eager. Isn't there a lazy way to do this? */
- xaccAccountRecomputeBalance (acc);
-
-
- gen_event (split);
- xaccFreeSplit (split);
- return TRUE;
-}
-
-/********************************************************************\
-\********************************************************************/
-
void
xaccTransAppendSplit (Transaction *trans, Split *split)
{
@@ -2221,101 +1252,7 @@
qof_commit_edit(QOF_INSTANCE(trans));
}
-/********************************************************************\
- * sorting comparison function
- *
- * returns a negative value if transaction a is dated earlier than b,
- * returns a positive value if transaction a is dated later than b,
- *
- * This function tries very hard to uniquely order all transactions.
- * If two transactions occur on the same date, then their "num" fields
- * are compared. If the num fields are identical, then the description
- * fields are compared. If these are identical, then the memo fields
- * are compared. Hopefully, there will not be any transactions that
- * occur on the same day that have all three of these values identical.
- *
- * Note that being able to establish this kind of absolute order is
- * important for some of the ledger display functions.
- *
- * Yes, this kind of code dependency is ugly, but the alternatives seem
- * ugly too.
- *
-\********************************************************************/
-
-
-#define DATE_CMP(aaa,bbb,field) { \
- /* if dates differ, return */ \
- if ( (aaa->field.tv_sec) < \
- (bbb->field.tv_sec)) { \
- return -1; \
- } else \
- if ( (aaa->field.tv_sec) > \
- (bbb->field.tv_sec)) { \
- return +1; \
- } \
- \
- /* else, seconds match. check nanoseconds */ \
- if ( (aaa->field.tv_nsec) < \
- (bbb->field.tv_nsec)) { \
- return -1; \
- } else \
- if ( (aaa->field.tv_nsec) > \
- (bbb->field.tv_nsec)) { \
- return +1; \
- } \
-}
-
-
-
int
-xaccSplitDateOrder (const Split *sa, const Split *sb)
-{
- int retval;
- int comp;
- char *da, *db;
-
- if (sa == sb) return 0;
- /* nothing is always less than something */
- if (!sa && sb) return -1;
- if (sa && !sb) return +1;
-
- retval = xaccTransOrder (sa->parent, sb->parent);
- if (retval) return retval;
-
- /* otherwise, sort on memo strings */
- da = sa->memo;
- db = sb->memo;
- SAFE_STRCMP (da, db);
-
- /* otherwise, sort on action strings */
- da = sa->action;
- db = sb->action;
- SAFE_STRCMP (da, db);
-
- /* the reconciled flag ... */
- if (sa->reconciled < sb->reconciled) return -1;
- if (sa->reconciled > sb->reconciled) return +1;
-
- /* compare amounts */
- comp = gnc_numeric_compare(xaccSplitGetAmount(sa), xaccSplitGetAmount (sb));
- if (comp < 0) return -1;
- if (comp > 0) return +1;
-
- comp = gnc_numeric_compare(xaccSplitGetValue(sa), xaccSplitGetValue (sb));
- if (comp < 0) return -1;
- if (comp > 0) return +1;
-
- /* if dates differ, return */
- DATE_CMP(sa,sb,date_reconciled);
-
- /* else, sort on guid - keeps sort stable. */
- retval = guid_compare(&(sa->inst.entity.guid), &(sb->inst.entity.guid));
- if (retval) return retval;
-
- return 0;
-}
-
-int
xaccTransOrder (const Transaction *ta, const Transaction *tb)
{
char *da, *db;
@@ -2346,162 +1283,6 @@
return guid_compare(&(ta->inst.entity.guid), &(tb->inst.entity.guid));
}
-static gboolean
-get_corr_account_split(const Split *sa, Split **retval)
-{
-
- Split *current_split;
- GList *node;
- gnc_numeric sa_value, current_value;
- gboolean sa_value_positive, current_value_positive, seen_different = FALSE;
-
- *retval = NULL;
- g_return_val_if_fail(sa, TRUE);
-
- sa_value = xaccSplitGetValue (sa);
- sa_value_positive = gnc_numeric_positive_p(sa_value);
-
- for (node = sa->parent->splits; node; node = node->next)
- {
- current_split = node->data;
- if (current_split == sa) continue;
-
- current_value = xaccSplitGetValue (current_split);
- current_value_positive = gnc_numeric_positive_p(current_value);
- if ((sa_value_positive && !current_value_positive) ||
- (!sa_value_positive && current_value_positive)) {
- if (seen_different) {
- *retval = NULL;
- return TRUE;
- } else {
- *retval = current_split;
- seen_different = TRUE;
- }
- }
- }
- return FALSE;
-}
-
-/* TODO: these static consts can be shared. */
-const char *
-xaccSplitGetCorrAccountName(const Split *sa)
-{
- static const char *split_const = NULL;
- Split *other_split;
-
- if (get_corr_account_split(sa, &other_split))
- {
- if (!split_const)
- split_const = _("-- Split Transaction --");
-
- return split_const;
- }
-
- return xaccAccountGetName(other_split->acc);
-}
-
-char *
-xaccSplitGetCorrAccountFullName(const Split *sa, char separator)
-{
- static const char *split_const = NULL;
- Split *other_split;
-
- if (get_corr_account_split(sa, &other_split))
- {
- if (!split_const)
- split_const = _("-- Split Transaction --");
-
- return g_strdup(split_const);
- }
- return xaccAccountGetFullName(other_split->acc, separator);
-}
-
-const char *
-xaccSplitGetCorrAccountCode(const Split *sa)
-{
- static const char *split_const = NULL;
- Split *other_split;
-
- if (get_corr_account_split(sa, &other_split))
- {
- if (!split_const)
- split_const = _("Split");
-
- return split_const;
- }
- return xaccAccountGetCode(other_split->acc);
-}
-
-/* TODO: It's not too hard to make this function avoid the malloc/free. */
-int
-xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
-{
- Account *aa, *ab;
- char *full_a, *full_b;
- int retval;
- if (!sa && !sb) return 0;
- if (!sa) return -1;
- if (!sb) return 1;
-
- aa = sa->acc;
- ab = sb->acc;
- full_a = xaccAccountGetFullName(aa, ':');
- full_b = xaccAccountGetFullName(ab, ':');
- /* for comparison purposes it doesn't matter what we use as a separator */
- retval = safe_strcmp(full_a, full_b);
- g_free(full_a);
- g_free(full_b);
- return retval;
-}
-
-
-int
-xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
-{
- Account *aa, *ab;
- if (!sa && !sb) return 0;
- if (!sa) return -1;
- if (!sb) return 1;
-
- aa = sa->acc;
- ab = sb->acc;
-
- return safe_strcmp(xaccAccountGetName(aa), xaccAccountGetName(ab));
-}
-
-int
-xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
-{
- char *ca, *cb;
- int retval;
- if (!sa && !sb) return 0;
- if (!sa) return -1;
- if (!sb) return 1;
-
- /* doesn't matter what separator we use
- * as long as they are the same
- */
-
- ca = xaccSplitGetCorrAccountFullName(sa, ':');
- cb = xaccSplitGetCorrAccountFullName(sb, ':');
- retval = safe_strcmp(ca, cb);
- g_free(ca);
- g_free(cb);
- return retval;
-}
-
-int
-xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
-{
- const char *ca, *cb;
- if (!sa && !sb) return 0;
- if (!sa) return -1;
- if (!sb) return 1;
-
- ca = xaccSplitGetCorrAccountCode(sa);
- cb = xaccSplitGetCorrAccountCode(sb);
- return safe_strcmp(ca, cb);
-}
/********************************************************************\
\********************************************************************/
@@ -2895,243 +1676,7 @@
/********************************************************************\
\********************************************************************/
-static void
-qofSplitSetMemo (Split *split, const char* memo)
-{
- gchar *tmp;
- g_return_if_fail(split);
- tmp = gnc_string_cache_insert((gpointer) memo);
- gnc_string_cache_remove(split->memo);
- split->memo = tmp;
-}
-
-void
-xaccSplitSetMemo (Split *split, const char *memo)
-{
- char * tmp;
- if (!split || !memo) return;
- check_open (split->parent);
-
- tmp = gnc_string_cache_insert((gpointer) memo);
- gnc_string_cache_remove(split->memo);
- split->memo = tmp;
-}
-
-static void
-qofSplitSetAction (Split *split, const char *actn)
-{
- g_return_if_fail(split);
- split->action = g_strdup(actn);
-}
-
-void
-xaccSplitSetAction (Split *split, const char *actn)
-{
- char * tmp;
- if (!split || !actn) return;
- check_open (split->parent);
-
- tmp = gnc_string_cache_insert((gpointer) actn);
- gnc_string_cache_remove(split->action);
- split->action = tmp;
-}
-
-static void
-qofSplitSetReconcile (Split *split, char recn)
-{
- g_return_if_fail(split);
- switch (recn)
- {
- case NREC:
- case CREC:
- case YREC:
- case FREC:
- case VREC:
- split->reconciled = recn;
- mark_split (split);
- xaccAccountRecomputeBalance (split->acc);
- break;
- default:
- PERR("Bad reconciled flag");
- }
-}
-
-void
-xaccSplitSetReconcile (Split *split, char recn)
-{
- if (!split || split->reconciled == recn) return;
- check_open (split->parent);
-
- switch (recn)
- {
- case NREC:
- case CREC:
- case YREC:
- case FREC:
- case VREC:
- split->reconciled = recn;
- mark_split (split);
- xaccAccountRecomputeBalance (split->acc);
- break;
- default:
- PERR("Bad reconciled flag");
- }
-}
-
-void
-xaccSplitSetDateReconciledSecs (Split *split, time_t secs)
-{
- if (!split) return;
- check_open (split->parent);
-
- split->date_reconciled.tv_sec = secs;
- split->date_reconciled.tv_nsec = 0;
-}
-
-void
-xaccSplitSetDateReconciledTS (Split *split, Timespec *ts)
-{
- if (!split || !ts) return;
- check_open (split->parent);
-
- split->date_reconciled = *ts;
-}
-
-void
-xaccSplitGetDateReconciledTS (const Split * split, Timespec *ts)
-{
- if (!split || !ts) return;
- *ts = (split->date_reconciled);
-}
-
-Timespec
-xaccSplitRetDateReconciledTS (const Split * split)
-{
- Timespec ts = {0,0};
- return split ? split->date_reconciled : ts;
-}
-
-/********************************************************************\
-\********************************************************************/
-
-/* return the parent transaction of the split */
-Transaction *
-xaccSplitGetParent (const Split *split)
-{
- return split ? split->parent : NULL;
-}
-
-GNCLot *
-xaccSplitGetLot (const Split *split)
-{
- return split ? split->lot : NULL;
-}
-
-const char *
-xaccSplitGetMemo (const Split *split)
-{
- return split ? split->memo : NULL;
-}
-
-const char *
-xaccSplitGetAction (const Split *split)
-{
- return split ? split->action : NULL;
-}
-
-char
-xaccSplitGetReconcile (const Split *split)
-{
- return split ? split->reconciled : ' ';
-}
-
-
-gnc_numeric
-xaccSplitGetAmount (const Split * split)
-{
- return split ? split->amount : gnc_numeric_zero();
-}
-
-gnc_numeric
-xaccSplitGetValue (const Split * split)
-{
- return split ? split->value : gnc_numeric_zero();
-}
-
-gnc_numeric
-xaccSplitGetSharePrice (const Split * split)
-{
- gnc_numeric amt, val, price;
- if (!split) return gnc_numeric_create(1, 1);
-
-
- /* if amount == 0 and value == 0, then return 1.
- * if amount == 0 and value != 0 then return 0.
- * otherwise return value/amount
- */
-
- amt = xaccSplitGetAmount(split);
- val = xaccSplitGetValue(split);
- if (gnc_numeric_zero_p(amt))
- {
- if (gnc_numeric_zero_p(val))
- return gnc_numeric_create(1, 1);
- return gnc_numeric_create(0, 1);
- }
- price = gnc_numeric_div(val, amt,
- GNC_DENOM_AUTO,
- GNC_HOW_DENOM_SIGFIGS(PRICE_SIGFIGS) |
- GNC_HOW_RND_ROUND);
-
- /* During random checks we can get some very weird prices. Let's
- * handle some overflow and other error conditions by returning
- * zero. But still print an error to let us know it happened.
- */
- if (gnc_numeric_check(price))
- {
- PERR("Computing share price failed (%d): [ %" G_GINT64_FORMAT " / %"
- G_GINT64_FORMAT " ] / [ %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " ]",
- gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
- return gnc_numeric_create(0,1);
- }
-
- return price;
-}
-
-/********************************************************************\
-\********************************************************************/
-
-QofBook *
-xaccSplitGetBook (const Split *split)
-{
- return qof_instance_get_book(QOF_INSTANCE(split));
-}
-
-const char *
-xaccSplitGetType(const Split *s)
-{
- char *split_type;
-
- if (!s) return NULL;
- split_type = kvp_frame_get_string(s->inst.kvp_data, "split-type");
- return split_type ? split_type : "normal";
-}
-
-/* reconfigure a split to be a stock split - after this, you shouldn't
- mess with the value, just the amount. */
-void
-xaccSplitMakeStockSplit(Split *s)
-{
- check_open (s->parent);
-
- s->value = gnc_numeric_zero();
- kvp_frame_set_str(s->inst.kvp_data, "split-type", "stock-split");
- SET_GAINS_VDIRTY(s);
- mark_split(s);
-}
-
-
/* ====================================================================== */
static int
@@ -3189,73 +1734,12 @@
/********************************************************************\
\********************************************************************/
-/* In the old world, the 'other split' was the other split of a
- * transaction that contained only two splits. In the new world,
- * a split may have been cut up between multiple lots, although
- * in a conceptual sense, if lots hadn't been used, there would be
- * only a pair. So we handle this conceptual case: we can still
- * identify, unambiguously, the 'other' split when 'this' split
- * as been cut up across lots. We do this by looking for the
- * 'lot-split' keyword, which occurs only in cut-up splits.
- */
-Split *
-xaccSplitGetOtherSplit (const Split *split)
-{
- SplitList *node;
- Transaction *trans;
- int count;
- Split *other = NULL;
- KvpValue *sva;
-
- if (!split) return NULL;
- trans = split->parent;
- if (!trans) return NULL;
-
-#ifdef OLD_ALGO_HAS_ONLY_TWO_SPLITS
- Split *s1, *s2;
- if (g_list_length (trans->splits) != 2) return NULL;
-
- s1 = g_list_nth_data (trans->splits, 0);
- s2 = g_list_nth_data (trans->splits, 1);
-
- if (s1 == split) return s2;
- return s1;
-#endif
-
- count = g_list_length (trans->splits);
- sva = kvp_frame_get_slot (split->inst.kvp_data, "lot-split");
- if (!sva && (2 != count)) return NULL;
-
- for (node = trans->splits; node; node = node->next)
- {
- Split *s = node->data;
- if (s == split) { --count; continue; }
- if (kvp_frame_get_slot (s->inst.kvp_data, "lot-split")) { --count; continue; }
- other = s;
- }
- return (1 == count) ? other : NULL;
-}
-
-/********************************************************************\
-\********************************************************************/
-
-gboolean
-xaccIsPeerSplit (const Split *sa, const Split *sb)
-{
- return (sa && sb && (sa->parent == sb->parent));
-}
-
-
-/********************************************************************\
-\********************************************************************/
-
void
xaccTransVoid(Transaction *trans, const char *reason)
{
KvpFrame *frame;
KvpValue *val;
- gnc_numeric zero = gnc_numeric_zero();
GList *split_list;
Timespec now;
char iso8601_str[ISO_DATELENGTH+1] = "";
@@ -3278,17 +1762,8 @@
for (split_list = trans->splits; split_list; split_list = split_list->next)
{
- Split * split = split_list->data;
- frame = split->inst.kvp_data;
-
- kvp_frame_set_gnc_numeric(frame, void_former_amt_str,
- xaccSplitGetAmount(split));
- kvp_frame_set_gnc_numeric(frame, void_former_val_str,
- xaccSplitGetValue(split));
-
- xaccSplitSetAmount (split, zero);
- xaccSplitSetValue (split, zero);
- xaccSplitSetReconcile(split, VREC);
+ Split * split = split_list->data;
+ xaccSplitVoid(split);
}
/* Dirtying taken care of by SetReadOnly */
@@ -3310,20 +1785,6 @@
return kvp_frame_get_string(trans->inst.kvp_data, void_reason_str);
}
-gnc_numeric
-xaccSplitVoidFormerAmount(const Split *split)
-{
- g_return_val_if_fail(split, gnc_numeric_zero());
- return kvp_frame_get_numeric(split->inst.kvp_data, void_former_amt_str);
-}
-
-gnc_numeric
-xaccSplitVoidFormerValue(const Split *split)
-{
- g_return_val_if_fail(split, gnc_numeric_zero());
- return kvp_frame_get_numeric(split->inst.kvp_data, void_former_val_str);
-}
-
Timespec
xaccTransGetVoidTime(const Transaction *tr)
{
@@ -3341,9 +1802,7 @@
{
KvpFrame *frame;
KvpValue *val;
- gnc_numeric amt;
GList *split_list;
- Split *split;
g_return_if_fail(trans);
@@ -3361,20 +1820,8 @@
for (split_list = trans->splits; split_list; split_list = split_list->next)
{
- split = split_list->data;
- frame = split->inst.kvp_data;
-
- val = kvp_frame_get_slot(frame, void_former_amt_str);
- amt = kvp_value_get_numeric(val);
- xaccSplitSetAmount (split, amt);
- kvp_frame_set_slot(frame, void_former_amt_str, NULL);
-
- val = kvp_frame_get_slot(frame, void_former_val_str);
- amt = kvp_value_get_numeric(val);
- xaccSplitSetValue (split, amt);
- kvp_frame_set_slot(frame, void_former_val_str, NULL);
-
- xaccSplitSetReconcile(split, NREC);
+ Split *split = split_list->data;
+ xaccSplitUnvoid(split);
}
/* Dirtying taken care of by ClearReadOnly */
@@ -3414,132 +1861,6 @@
/* QofObject function implementation */
/* Hook into the QofObject registry */
-
-static QofObject split_object_def = {
- interface_version: QOF_OBJECT_VERSION,
- e_type: GNC_ID_SPLIT,
- type_label: "Split",
- create: (gpointer)xaccMallocSplit,
- book_begin: NULL,
- book_end: NULL,
- is_dirty: NULL,
- mark_clean: NULL,
- foreach: qof_collection_foreach,
- printable: (const char* (*)(gpointer)) xaccSplitGetMemo,
- version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
-};
-
-static gpointer
-split_account_guid_getter (gpointer obj, const QofParam *p)
-{
- Split *s = obj;
- Account *acc;
-
- if (!s) return NULL;
- acc = xaccSplitGetAccount (s);
- if (!acc) return NULL;
- return ((gpointer)xaccAccountGetGUID (acc));
-}
-
-static double /* internal use only */
-DxaccSplitGetShareAmount (const Split * split)
-{
- return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
-}
-
-static gpointer
-no_op (gpointer obj, const QofParam *p)
-{
- return obj;
-}
-
-static void
-qofSplitSetParentTrans(Split *s, QofEntity *ent)
-{
- Transaction *trans = (Transaction*)ent;
-
- g_return_if_fail(trans);
- xaccTransAppendSplit(trans, s);
-}
-
-static void
-qofSplitSetAccount(Split *s, QofEntity *ent)
-{
- Account *acc = (Account*)ent;
-
- g_return_if_fail(acc);
- xaccAccountInsertSplit(acc, s);
-}
-
-gboolean xaccSplitRegister (void)
-{
- static const QofParam params[] = {
- { SPLIT_DATE_RECONCILED, QOF_TYPE_DATE,
- (QofAccessFunc)xaccSplitRetDateReconciledTS,
- (QofSetterFunc)xaccSplitSetDateReconciledTS },
-
- /* d-* are deprecated query params, should not be used in new
- * queries, should be removed from old queries. */
- { "d-share-amount", QOF_TYPE_DOUBLE,
- (QofAccessFunc)DxaccSplitGetShareAmount, NULL },
- { "d-share-int64", QOF_TYPE_INT64,
- (QofAccessFunc)qof_entity_get_guid, NULL },
- { SPLIT_BALANCE, QOF_TYPE_NUMERIC,
- (QofAccessFunc)xaccSplitGetBalance, NULL },
- { SPLIT_CLEARED_BALANCE, QOF_TYPE_NUMERIC,
- (QofAccessFunc)xaccSplitGetClearedBalance, NULL },
- { SPLIT_RECONCILED_BALANCE, QOF_TYPE_NUMERIC,
- (QofAccessFunc)xaccSplitGetReconciledBalance, NULL },
- { SPLIT_MEMO, QOF_TYPE_STRING,
- (QofAccessFunc)xaccSplitGetMemo, (QofSetterFunc)qofSplitSetMemo },
- { SPLIT_ACTION, QOF_TYPE_STRING,
- (QofAccessFunc)xaccSplitGetAction, (QofSetterFunc)qofSplitSetAction },
- { SPLIT_RECONCILE, QOF_TYPE_CHAR,
- (QofAccessFunc)xaccSplitGetReconcile,
- (QofSetterFunc)qofSplitSetReconcile },
- { SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
- (QofAccessFunc)xaccSplitGetAmount, (QofSetterFunc)qofSplitSetAmount },
- { SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
- (QofAccessFunc)xaccSplitGetSharePrice,
- (QofSetterFunc)qofSplitSetSharePrice },
- { SPLIT_VALUE, QOF_TYPE_DEBCRED,
- (QofAccessFunc)xaccSplitGetValue, (QofSetterFunc)qofSplitSetValue },
- { SPLIT_TYPE, QOF_TYPE_STRING, (QofAccessFunc)xaccSplitGetType, NULL },
- { SPLIT_VOIDED_AMOUNT, QOF_TYPE_NUMERIC,
- (QofAccessFunc)xaccSplitVoidFormerAmount, NULL },
- { SPLIT_VOIDED_VALUE, QOF_TYPE_NUMERIC,
- (QofAccessFunc)xaccSplitVoidFormerValue, NULL },
- { SPLIT_LOT, GNC_ID_LOT, (QofAccessFunc)xaccSplitGetLot, NULL },
- { SPLIT_TRANS, GNC_ID_TRANS,
- (QofAccessFunc)xaccSplitGetParent,
- (QofSetterFunc)qofSplitSetParentTrans },
- { SPLIT_ACCOUNT, GNC_ID_ACCOUNT,
- (QofAccessFunc)xaccSplitGetAccount, (QofSetterFunc)qofSplitSetAccount },
- { SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, NULL },
-/* these are no-ops to register the parameter names (for sorting) but
- they return an allocated object which getters cannot do. */
- { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, NULL },
- { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, NULL },
- { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, NULL },
- { SPLIT_KVP, QOF_TYPE_KVP, (QofAccessFunc)xaccSplitGetSlots, NULL },
- { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, NULL },
- { QOF_PARAM_GUID, QOF_TYPE_GUID,
- (QofAccessFunc)qof_entity_get_guid, NULL },
- { NULL },
- };
-
- qof_class_register (GNC_ID_SPLIT, (QofSortFunc)xaccSplitDateOrder, params);
- qof_class_register (SPLIT_ACCT_FULLNAME,
- (QofSortFunc)xaccSplitCompareAccountFullNames, NULL);
- qof_class_register (SPLIT_CORR_ACCT_NAME,
- (QofSortFunc)xaccSplitCompareOtherAccountFullNames,
- NULL);
- qof_class_register (SPLIT_CORR_ACCT_CODE,
- (QofSortFunc)xaccSplitCompareOtherAccountCodes, NULL);
-
- return qof_object_register (&split_object_def);
-}
-
static QofObject trans_object_def = {
interface_version: QOF_OBJECT_VERSION,
e_type: GNC_ID_TRANS,
Modified: gnucash/trunk/src/engine/Transaction.h
===================================================================
--- gnucash/trunk/src/engine/Transaction.h 2006-02-22 17:41:58 UTC (rev 13362)
+++ gnucash/trunk/src/engine/Transaction.h 2006-02-22 21:52:46 UTC (rev 13363)
@@ -90,22 +90,8 @@
#include "gnc-commodity.h"
#include "gnc-engine.h"
+#include "Split.h"
-/** @name Split Reconciled field values
-
- If you change these
- be sure to change gnc-ui-util.c:gnc_get_reconciled_str() and
- associated functions
-
-@{
-*/
-#define CREC 'c' /**< The Split has been cleared */
-#define YREC 'y' /**< The Split has been reconciled */
-#define FREC 'f' /**< frozen into accounting period */
-#define NREC 'n' /**< not reconciled or cleared */
-#define VREC 'v' /**< split is void */
-/** @} */
-
/** @name Transaction Type field values
@{
*/
@@ -348,12 +334,6 @@
*/
gnc_numeric xaccTransGetAccountConvRate(Transaction *txn, Account *acc);
-/* Convert the amount/value of the Split for viewing in the account --
- * in particular we want to convert the Split to be in to_commodity.
- * Returns the amount.
- */
-gnc_numeric xaccSplitConvertAmount (Split *split, Account * account);
-
/** Get the account balance for the specified account after the last
split in the specified transaction. */
gnc_numeric xaccTransGetAccountBalance (const Transaction *trans,
@@ -449,363 +429,7 @@
/** @} */
-/*-----------------------------------------------------------------------
- * Splits
- *-----------------------------------------------------------------------*/
-/** @name Split general getters/setters
-@{
-*/
-
-/** Constructor. */
-Split * xaccMallocSplit (QofBook *book);
-
-/* Reinit a previously malloc'd split. Split remains in the book it
- was already in, and the QofEntity portions also remain unchanged.
- It's basically the data elements that are reverted to default
- values. */
-void xaccSplitReinit(Split * split);
-
-/** Destructor.
- *
- * The xaccSplitDestroy() method will update its parent account and
- * transaction in a consistent manner, resulting in the complete
- * unlinking of the split, and the freeing of its associated memory.
- * The goal of this routine is to perform the removal and destruction
- * of the split in an atomic fashion, with no chance of accidentally
- * leaving the accounting structure out-of-balance or otherwise
- * inconsistent.
- *
- * If the deletion of the split leaves the transaction with no splits,
- * then the transaction will be marked for deletion. (It will not be
- * deleted until the xaccTransCommitEdit() routine is called.)
- *
- * @return TRUE upon successful deletion of the split. FALSE when
- * the parenting Transaction is a read-only one.
- */
-gboolean xaccSplitDestroy (Split *split);
-
-/** Returns the book of this split, i.e. the entity where this split
- * is stored. */
-QofBook * xaccSplitGetBook (const Split *split);
-
-/** Returns the account of this split, which was set through
- * xaccAccountInsertSplit(). */
-Account * xaccSplitGetAccount (const Split *split);
-
-/** Returns the parent transaction of the split, which was set through
- * xaccTransAppendSplit(). */
-Transaction * xaccSplitGetParent (const Split *split);
-
-/** Returns the pointer to the debited/credited Lot where this split
- * belongs to, or NULL if it doesn't belong to any. */
-GNCLot * xaccSplitGetLot (const Split *split);
-
-
-/** Returns the KvpFrame slots of this split for direct editing.
- *
- * Split slots are used to store arbitrary strings, numbers, and
- * structures which aren't members of the transaction struct. See
- * kvp_doc.txt for reserved slot names.
- */
-KvpFrame *xaccSplitGetSlots(const Split *split);
-
-/** Set the KvpFrame slots of this split to the given frm by directly
- * using the frm pointer (i.e. non-copying). */
-void xaccSplitSetSlots_nc(Split *s, KvpFrame *frm);
-
-
-/** The memo is an arbitrary string associated with a split. It is
- * intended to hold a short (zero to forty character) string that is
- * displayed by the GUI along with this split. Users typically type
- * in free form text from the GUI. */
-void xaccSplitSetMemo (Split *split, const char *memo);
-
-/** Returns the memo string. */
-const char * xaccSplitGetMemo (const Split *split);
-
-/** The Action is an arbitrary user-assigned string.
- * The action field is an arbitrary user-assigned value.
- * It is meant to be a very short (one to ten cahracter) string that
- * signifies the "type" of this split, such as e.g. Buy, Sell, Div,
- * Withdraw, Deposit, ATM, Check, etc. The idea is that this field
- * can be used to create custom reports or graphs of data. */
-void xaccSplitSetAction (Split *split, const char *action);
-
-/** Returns the action string. */
-const char * xaccSplitGetAction (const Split *split);
-/** @} */
-
-/** @name Split Date getters/setters
-@{
-*/
-/** Set the reconcile flag. The Reconcile flag is a single char, whose
- * values are typically are 'n', 'y', 'c'. In Transaction.h, macros
- * are defined for typical values (e.g. CREC, YREC). */
-void xaccSplitSetReconcile (Split *split, char reconciled_flag);
-/** Returns the value of the reconcile flag. */
-char xaccSplitGetReconcile (const Split *split);
-
-/** Set the date on which this split was reconciled by specifying the
- * time as time_t. */
-void xaccSplitSetDateReconciledSecs (Split *split, time_t time);
-/** Set the date on which this split was reconciled by specifying the
- * time as Timespec. */
-void xaccSplitSetDateReconciledTS (Split *split, Timespec *ts);
-/** Get the date on which this split was reconciled by having it
- * written into the Timespec that 'ts' is pointing to. */
-void xaccSplitGetDateReconciledTS (const Split *split,
- Timespec *ts);
-/** Returns the date (as Timespec) on which this split was reconciled. */
-Timespec xaccSplitRetDateReconciledTS (const Split *split);
-
-/** @} */
-
-
-/** @name Split amount getters/setters
- *
- * 'value' vs. 'amount' of a Split: The 'value' is the amount of the
- * _transaction_ balancing commodity (i.e. currency) involved,
- * 'amount' is the amount of the _account's_ commodity involved.
-@{
-*/
-
-/** The xaccSplitSetAmount() method sets the amount in the account's
- * commodity that the split should have.
- *
- * The following four setter functions set the prices and amounts.
- * All of the routines always maintain balance: that is, invoking any
- * of them will cause other splits in the transaction to be modified
- * so that the net value of the transaction is zero.
- *
- * IMPORTANT: The split should be parented by an account before
- * any of these routines are invoked! This is because the actual
- * setting of amounts/values requires SCU settings from the account.
- * If these are not available, then amounts/values will be set to
- * -1/0, which is an invalid value. I beleive this order dependency
- * is a bug, but I'm too lazy to find, fix & test at the moment ...
- *
- * @note If you use this on a newly created transaction, make sure
- * that the 'value' is also set so that it doesn't remain zero.
- */
-void xaccSplitSetAmount (Split *split, gnc_numeric amount);
-
-/** Returns the amount of the split in the account's commodity.
- * Note that for cap-gains splits, this is slaved to the transaction
- * that is causing the gains to occur.
- */
-gnc_numeric xaccSplitGetAmount (const Split * split);
-
-/** The xaccSplitSetValue() method sets the value of this split in the
- * transaction's commodity.
- *
- * @note If you use this on a newly created transaction, make sure
- * that the 'amount' is also set so that it doesn't remain zero.
- */
-void xaccSplitSetValue (Split *split, gnc_numeric value);
-
-/** Returns the value of this split in the transaction's commodity.
- * Note that for cap-gains splits, this is slaved to the transaction
- * that is causing the gains to occur.
-*/
-gnc_numeric xaccSplitGetValue (const Split * split);
-
-/** The xaccSplitSetSharePriceAndAmount() method will simultaneously
- * update the share price and the number of shares. This is a utility
- * routine that is equivalent to a xaccSplitSetSharePrice() followed
- * by and xaccSplitSetAmount(), except that it incurs the processing
- * overhead of balancing only once, instead of twice. */
-void xaccSplitSetSharePriceAndAmount (Split *split,
- gnc_numeric price,
- gnc_numeric amount);
-
-/** Returns the price of the split, that is, the value divided by the
- * amount. If the amount is zero, returns a gnc_numeric of value
- * one. */
-gnc_numeric xaccSplitGetSharePrice (const Split * split);
-
-/** Depending on the base_currency, set either the value or the amount
- * of this split or both: If the base_currency is the transaction's
- * commodity, set the value. If it is the account's commodity, set the
- * amount. If both, set both.
- *
- * @note <b>WATCH OUT:</b> When using this function and the
- * transaction's and account's commodities are different, the amount
- * or the value will be left as zero. This might screw up the
- * multi-currency handling code in the register. So please think twice
- * whether you need this function -- using xaccSplitSetValue()
- * together with xaccSplitSetAmount() is definitely the better and
- * safer solution!
- */
-void xaccSplitSetBaseValue (Split *split, gnc_numeric value,
- const gnc_commodity * base_currency);
-
-/** Depending on the base_currency, return either the value or the
- * amount of this split: If the base_curreny is the transaction's
- * commodity, return the value. If it is the account's commodity,
- * return the amount. If it is neither print a warning message and
- * return gnc_numeric_zero().
- */
-gnc_numeric xaccSplitGetBaseValue (const Split *split,
- const gnc_commodity * base_currency);
-
-/** Returns the running balance up to and including the indicated split.
- * The balance is the currency-denominated balance. For accounts
- * with non-unit share prices, it is correctly adjusted for
- * share prices.
- *
- * Returns the running balance up to & including the indicated split.
- */
-gnc_numeric xaccSplitGetBalance (const Split *split);
-
-/**
- * The cleared-balance is the currency-denominated balance
- * of all transactions that have been marked as cleared or reconciled.
- * It is correctly adjusted for price fluctuations.
- *
- * Returns the running balance up to & including the indicated split.
- */
-gnc_numeric xaccSplitGetClearedBalance (const Split *split);
-
-/**
- * Returns the reconciled-balance of this split. The
- * reconciled-balance is the currency-denominated balance of all
- * transactions that have been marked as reconciled.
- *
- * Returns the running balance up to & including the indicated split.
- */
-gnc_numeric xaccSplitGetReconciledBalance (const Split *split);
-
-/** @} */
-
-/** @name Split utility functions
-@{
-*/
-
-/* Get a GList of unique transactions containing the given list of Splits. */
-GList *xaccSplitListGetUniqueTransactions(const GList *splits);
-
-/** Equality.
- *
- * @param sa First split to compare
- * @param sb Second split to compare
- *
- * @param check_guids If TRUE, try a guid_equal() on the GUIDs of both
- * splits if their pointers are not equal in the first place.
- *
- * @param check_balances If TRUE, compare balances between the two
- * splits. Balances are recalculated whenever a split is added or
- * removed from an account, so YMMV on whether this should be set.
- *
- * @param check_txn_splits If the pointers are not equal, but
- * everything else so far is equal (including memo, amount, value,
- * kvp_frame), then, when comparing the parenting transactions with
- * xaccTransEqual(), set its argument check_splits to be TRUE.
- */
-gboolean xaccSplitEqual(const Split *sa, const Split *sb,
- gboolean check_guids,
- gboolean check_balances,
- gboolean check_txn_splits);
-
-/** The xaccSplitLookup() subroutine will return the
- * split associated with the given id, or NULL
- * if there is no such split. */
-Split * xaccSplitLookup (const GUID *guid, QofBook *book);
-#define xaccSplitLookupDirect(g,b) xaccSplitLookup(&(g),b)
-
-
-/**
- * The xaccSplitGetOtherSplit() is a convenience routine that returns
- * the other of a pair of splits. If there are more than two
- * splits, it returns NULL.
- */
-Split * xaccSplitGetOtherSplit (const Split *split);
-
-/** The xaccIsPeerSplit() is a convenience routine that returns TRUE
- * (a non-zero value) if the two splits share a common parent
- * transaction, else it returns FALSE (zero).
- */
-gboolean xaccIsPeerSplit (const Split *split_1, const Split *split_2);
-
-/** Returns the split type, which is either the string "normal", or
- * "stock-split" for a split from a stock split (pun intended? :-). */
-const char *xaccSplitGetType(const Split *s);
-
-/** Mark a split to be of type stock split - after this, you shouldn't
- modify the value anymore, just the amount. */
-void xaccSplitMakeStockSplit(Split *s);
-
-/**
- * The xaccSplitDateOrder(sa,sb) method is useful for sorting.
- * if sa and sb have different transactions, return their xaccTransOrder
- * return a negative value if split sa has a smaller currency-value than sb,
- * return a positive value if split sa has a larger currency-value than sb,
- * return a negative value if split sa has a smaller share-price than sb,
- * return a positive value if split sa has a larger share-price than sb,
- * then compares memo and action using the strcmp()
- * c-library routine, returning what strcmp would return.
- * Then it compares the reconciled flags, then the reconciled dates,
- * Finally, it returns zero if all of the above match.
- */
-int xaccSplitDateOrder (const Split *sa, const Split *sb);
-
-
-/*
- * These functions compare two splits by different criteria.
- *
- * These functions were added because converting strings to guile
- * for comparisons in the transaction report is terribly inefficient.
- * More may be added here in future if it turns out that other types
- * of comparisons also induces guile slowdowns.
- */
-
-/** Compare two splits by full name of account. Returns similar to
- * strcmp. */
-int xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb);
-/** Compare two splits by code of account. Returns similar to
- * strcmp. */
-int xaccSplitCompareAccountCodes(const Split *sa, const Split *sb);
-/** Compare two splits by full name of the other account. Returns
- * similar to strcmp. This function attempts to find the split on the
- * other side of a transaction and compare on it. */
-int xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb);
-/** Compare two splits by code of the other account. Returns similar
- * to strcmp. This function attempts to find the split on the
- * other side of a transaction and compare on it. */
-int xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb);
-
-
-/**
- * These functions take a split, get the corresponding split on the
- * "other side" of the transaction, and extract either the name or code
- * of that split, reverting to returning a constant "Split" if the
- * transaction has more than one split on the "other side". These
- * were added for the transaction report, and is in C because the code
- * was already written in C for the above functions and duplication
- * is silly.
- */
-
-char * xaccSplitGetCorrAccountFullName(const Split *sa, char seperator);
-/** document me */
-const char * xaccSplitGetCorrAccountName(const Split *sa);
-/** document me */
-const char * xaccSplitGetCorrAccountCode(const Split *sa);
-
-/** @} */
-
-
-
-/** @name Split deprecated functions
-@{
-*/
-
-/** @deprecated The xaccSplitSetSharePrice() method sets the price of the
- * split. DEPRECATED - set the value and amount instead. */
-void xaccSplitSetSharePrice (Split *split, gnc_numeric price);
-
-/** @} */
-
-
/********************************************************************\
* Miscellaneous utility routines.
\********************************************************************/
@@ -875,24 +499,6 @@
*/
char *xaccTransGetVoidReason(const Transaction *transaction);
-/** Returns the original pre-void amount of a split.
- *
- * @param split The split in question.
- *
- * @return A gnc_numeric containing the original value of this split.
- * Returns a gnc_numeric of zero upon error.
- */
-gnc_numeric xaccSplitVoidFormerAmount(const Split *split);
-
-/** Returns the original pre-void value of a split.
- *
- * @param split The split in question.
- *
- * @return A gnc_numeric containing the original amount of this split.
- * Returns a gnc_numeric of zero upon error.
- */
-gnc_numeric xaccSplitVoidFormerValue(const Split *split);
-
/** Returns the time that a transaction was voided.
*
* @param tr The transaction in question.
@@ -903,40 +509,6 @@
Timespec xaccTransGetVoidTime(const Transaction *tr);
/** @} */
-/** @name Split Parameter names
-
- * Note, if you want to get the equivalent of "ACCT_MATCH_ALL" you
- * need to create a search on the following parameter list:
- * SPLIT->SPLIT_TRANS->TRANS_SPLITLIST->SPLIT_ACCOUNT_GUID. If you do
- * this, you might want to use the ACCOUNT_MATCH_ALL_TYPE as the
- * override so the gnome-search dialog displays the right type.
- @{
-*/
-#define SPLIT_KVP "kvp"
-
-#define SPLIT_DATE_RECONCILED "date-reconciled"
-#define SPLIT_BALANCE "balance"
-#define SPLIT_CLEARED_BALANCE "cleared-balance"
-#define SPLIT_RECONCILED_BALANCE "reconciled-balance"
-#define SPLIT_MEMO "memo"
-#define SPLIT_ACTION "action"
-#define SPLIT_RECONCILE "reconcile-flag"
-#define SPLIT_AMOUNT "amount"
-#define SPLIT_SHARE_PRICE "share-price"
-#define SPLIT_VALUE "value"
-#define SPLIT_TYPE "type"
-#define SPLIT_VOIDED_AMOUNT "voided-amount"
-#define SPLIT_VOIDED_VALUE "voided-value"
-#define SPLIT_LOT "lot"
-#define SPLIT_TRANS "trans"
-#define SPLIT_ACCOUNT "account"
-#define SPLIT_ACCOUNT_GUID "account-guid" /**< for guid_match_all */
-/* used for SORTING ONLY */
-#define SPLIT_ACCT_FULLNAME "acct-fullname"
-#define SPLIT_CORR_ACCT_NAME "corr-acct-fullname"
-#define SPLIT_CORR_ACCT_CODE "corr-acct-code"
-/** @} */
-
/** @name Transaction Parameter names
@{
*/
@@ -959,10 +531,6 @@
#define RECONCILED_MATCH_TYPE "reconciled-match"
/** \deprecated */
-#define xaccSplitGetGUID(X) qof_entity_get_guid(QOF_ENTITY(X))
-/** \deprecated */
-#define xaccSplitReturnGUID(X) (X ? *(qof_entity_get_guid(QOF_ENTITY(X))) : *(guid_null()))
-/** \deprecated */
#define xaccTransGetBook(X) qof_instance_get_book (QOF_INSTANCE(X))
/** \deprecated */
#define xaccTransGetGUID(X) qof_entity_get_guid(QOF_ENTITY(X))
Modified: gnucash/trunk/src/engine/TransactionP.h
===================================================================
--- gnucash/trunk/src/engine/TransactionP.h 2006-02-22 17:41:58 UTC (rev 13362)
+++ gnucash/trunk/src/engine/TransactionP.h 2006-02-22 21:52:46 UTC (rev 13363)
@@ -51,6 +51,7 @@
#include <glib.h>
#include "gnc-engine.h" /* for typedefs */
+#include "SplitP.h"
#include "qof.h"
@@ -72,81 +73,6 @@
* A "split" is more commonly referred to as an "entry" in a "transaction".
*/
-/* Flags for handling cap-gains status */
-#define GAINS_STATUS_UNKNOWN 0xff
-#define GAINS_STATUS_CLEAN 0x0
-#define GAINS_STATUS_GAINS 0x3
-#define GAINS_STATUS_DATE_DIRTY 0x10
-#define GAINS_STATUS_AMNT_DIRTY 0x20
-#define GAINS_STATUS_VALU_DIRTY 0x40
-#define GAINS_STATUS_LOT_DIRTY 0x80
-#define GAINS_STATUS_ADIRTY (GAINS_STATUS_AMNT_DIRTY|GAINS_STATUS_LOT_DIRTY)
-#define GAINS_STATUS_VDIRTY (GAINS_STATUS_VALU_DIRTY)
-#define GAINS_STATUS_A_VDIRTY (GAINS_STATUS_AMNT_DIRTY|GAINS_STATUS_VALU_DIRTY|GAINS_STATUS_LOT_DIRTY)
-
-struct split_s
-{
- QofInstance inst;
-
- Account *acc; /* back-pointer to debited/credited account */
-
- GNCLot *lot; /* back-pointer to debited/credited lot */
-
- Transaction *parent; /* parent of split */
-
- /* The memo field is an arbitrary user-assiged value.
- * It is intended to hold a short (zero to forty character) string
- * that is displayed by the GUI along with this split.
- */
- char * memo;
-
- /* The action field is an arbitrary user-assigned value.
- * It is meant to be a very short (one to ten character) string that
- * signifies the "type" of this split, such as e.g. Buy, Sell, Div,
- * Withdraw, Deposit, ATM, Check, etc. The idea is that this field
- * can be used to create custom reports or graphs of data.
- */
- char * action; /* Buy, Sell, Div, etc. */
-
- Timespec date_reconciled; /* date split was reconciled */
- char reconciled; /* The reconciled field */
-
- /* gains is a flag used to track the relationship between
- * capital-gains splits. Depending on its value, this flag indicates
- * if this split is the source of gains, if this split is a record
- * of the gains, and if values are 'dirty' and need to be recomputed.
- */
- unsigned char gains;
-
- /* 'gains_split' is a convenience pointer used to track down the
- * other end of a cap-gains transaction pair. NULL if this split
- * doesn't involve cap gains.
- */
- Split *gains_split;
-
- /* 'value' is the quantity of the transaction balancing commodity
- * (i.e. currency) involved, 'amount' is the amount of the account's
- * commodity involved. */
- gnc_numeric value;
- gnc_numeric amount;
-
- /* -------------------------------------------------------------- */
- /* Below follow some 'temporary' fields */
-
- /* The various "balances" are the sum of all of the values of
- * all the splits in the account, up to and including this split.
- * These balances apply to a sorting order by date posted
- * (not by date entered). */
- gnc_numeric balance;
- gnc_numeric cleared_balance;
- gnc_numeric reconciled_balance;
-
- /* -------------------------------------------------------------- */
- /* Backend private expansion data */
- guint32 idata; /* used by the sql backend for kvp management */
-};
-
-
struct transaction_s
{
QofInstance inst; /* glbally unique id */
@@ -201,21 +127,6 @@
* call this on an existing transaction! */
#define xaccTransSetGUID(t,g) qof_entity_set_guid(QOF_ENTITY(t),g)
-/* Set the split's GUID. This should only be done when reading
- * a split from a datafile, or some other external source. Never
- * call this on an existing split! */
-#define xaccSplitSetGUID(s,g) qof_entity_set_guid(QOF_ENTITY(s),g)
-
-/* The xaccFreeSplit() method simply frees all memory associated
- * with the split. It does not verify that the split isn't
- * referenced in some account. If the split is referenced by an
- * account, then calling this method will leave the system in an
- * inconsistent state. This *will* lead to crashes and hangs.
- */
-void xaccFreeSplit (Split *split); /* frees memory */
-
-Split * xaccSplitClone (const Split *s);
-
/* This routine makes a 'duplicate' of the indicated transaction.
* This routine cannot be exposed publically since the duplicate
* is wrong in many ways: it is not issued a unique guid, and thus
@@ -227,11 +138,6 @@
*/
Transaction * xaccDupeTransaction (const Transaction *t);
-/* Compute the value of a list of splits in the given currency,
- * excluding the skip_me split. */
-gnc_numeric xaccSplitsComputeValue (GList *splits, Split * skip_me,
- const gnc_commodity * base_currency);
-
/* The xaccTransSet/GetVersion() routines set & get the version
* numbers on this transaction. The version number is used to manage
* multi-user updates. These routines are private because we don't
@@ -240,8 +146,7 @@
void xaccTransSetVersion (Transaction*, gint32);
gint32 xaccTransGetVersion (const Transaction*);
-/* Code to register Split and Transaction types with the engine */
-gboolean xaccSplitRegister (void);
+/* Code to register Transaction type with the engine */
gboolean xaccTransRegister (void);
/* The xaccTransactionGetBackend() subroutine will find the
@@ -264,22 +169,6 @@
void xaccEnableDataScrubbing(void);
void xaccDisableDataScrubbing(void);
-/* The xaccSplitDetermineGainStatus() routine will analyze the
- * the split, and try to set the internal status flags
- * appropriately for the split. These flags indicate if the split
- * represents cap gains, and if the gains value/amount needs to be
- * recomputed.
- */
-void xaccSplitDetermineGainStatus (Split *split);
-
-/* ---------------------------------------------------------------- */
-/* Depricated routines */
-void DxaccSplitSetSharePriceAndAmount (Split *split,
- double price,
- double amount);
-void DxaccSplitSetShareAmount (Split *split, double amount);
-
-
/** Set the KvpFrame slots of this transaction to the given frm by
* * directly using the frm pointer (i.e. non-copying).
* * XXX this is wrong, nedds to be replaced with a transactional thingy
@@ -287,6 +176,9 @@
* */
#define xaccTransSetSlots_nc(T,F) qof_instance_set_slots(QOF_INSTANCE(T),F)
+void xaccTransRemoveSplit (Transaction *trans, const Split *split);
+G_INLINE_FUNC void check_open (const Transaction *trans);
+
/*@}*/
More information about the gnucash-changes
mailing list