mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Delete unused Period.c and ifdeffed-away call to it
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@21194 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
@@ -177,7 +177,6 @@ src/engine/gnc-session-scm.c
|
||||
src/engine/gncTaxTable.c
|
||||
src/engine/gncVendor.c
|
||||
src/engine/kvp-scm.c
|
||||
src/engine/Period.c
|
||||
src/engine/policy.c
|
||||
src/engine/Query.c
|
||||
src/engine/Recurrence.c
|
||||
|
||||
@@ -15,7 +15,6 @@ AM_CPPFLAGS = \
|
||||
libgncmod_engine_la_SOURCES = \
|
||||
Account.c \
|
||||
Recurrence.c \
|
||||
Period.c \
|
||||
Query.c \
|
||||
SchedXaction.c \
|
||||
SX-book.c \
|
||||
@@ -68,7 +67,6 @@ gncinclude_HEADERS = \
|
||||
FreqSpec.h \
|
||||
Recurrence.h \
|
||||
GNCId.h \
|
||||
Period.h \
|
||||
SchedXaction.h \
|
||||
SX-book.h \
|
||||
SX-ttinfo.h \
|
||||
|
||||
@@ -1,888 +0,0 @@
|
||||
/********************************************************************\
|
||||
* Period.c -- Implement accounting Periods *
|
||||
* *
|
||||
* 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@gnu.org *
|
||||
\********************************************************************/
|
||||
/*
|
||||
* FILE:
|
||||
* Period.c
|
||||
*
|
||||
* FUNCTION:
|
||||
* Implement accounting periods, using design described in
|
||||
* src/doc/books.txt
|
||||
*
|
||||
* CAUTION: poorly tested.
|
||||
*
|
||||
* HISTORY:
|
||||
* Created by Linas Vepstas November 2001
|
||||
* Copyright (c) 2001-2003 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "AccountP.h"
|
||||
#include "qof.h"
|
||||
#include "gnc-lot.h"
|
||||
#include "gnc-pricedb.h"
|
||||
#include "gnc-pricedb-p.h"
|
||||
#include "Period.h"
|
||||
#include "Transaction.h"
|
||||
#include "TransactionP.h"
|
||||
|
||||
/* This static indicates the debugging module that this .o belongs to. */
|
||||
static QofLogModule log_module = GNC_MOD_BOOK;
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
static inline Account *
|
||||
xaccAccountLookupTwin (Account *acc, QofBook *book)
|
||||
{
|
||||
return (Account *) qof_instance_lookup_twin (QOF_INSTANCE(acc), book);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* Reparent transaction to new book. This routine does this by
|
||||
* deleting the transaction in the old book, and creating a copy
|
||||
* in the new book. While technically correct, this is maybe too
|
||||
* much churn on the backend ...
|
||||
*/
|
||||
|
||||
void
|
||||
gnc_book_insert_trans_clobber (QofBook *book, Transaction *trans)
|
||||
{
|
||||
QofCollection *col;
|
||||
Transaction *newtrans;
|
||||
GList *node;
|
||||
|
||||
if (!trans || !book) return;
|
||||
|
||||
/* If this is the same book, its a no-op. */
|
||||
if (qof_instance_get_book(trans) == book) return;
|
||||
|
||||
ENTER ("trans=%p %s", trans, trans->description);
|
||||
newtrans = xaccDupeTransaction (trans);
|
||||
for (node = newtrans->splits; node; node = node->next)
|
||||
{
|
||||
Split *s = node->data;
|
||||
s->parent = newtrans;
|
||||
}
|
||||
|
||||
/* Utterly wipe out the transaction from the old book. */
|
||||
xaccTransBeginEdit (trans);
|
||||
xaccTransDestroy (trans);
|
||||
xaccTransCommitEdit (trans);
|
||||
|
||||
/* Fiddle the transaction into place in the new book */
|
||||
col = qof_book_get_collection (book, GNC_ID_TRANS);
|
||||
qof_collection_insert_entity (col, &newtrans->inst);
|
||||
qof_instance_set_book(newtrans, book);
|
||||
|
||||
col = qof_book_get_collection (book, GNC_ID_SPLIT);
|
||||
xaccTransBeginEdit (newtrans);
|
||||
for (node = newtrans->splits; node; node = node->next)
|
||||
{
|
||||
Account *twin;
|
||||
Split *s = node->data;
|
||||
|
||||
/* move the split into the new book ... */
|
||||
qof_instance_set_book(s, book);
|
||||
qof_collection_insert_entity(col, &s->inst);
|
||||
|
||||
/* find the twin account, and re-parent to that. */
|
||||
twin = xaccAccountLookupTwin (s->acc, book);
|
||||
if (!twin)
|
||||
{
|
||||
PERR ("near-fatal: twin account not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
xaccAccountInsertSplit (twin, s);
|
||||
g_object_set(twin, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
xaccTransCommitEdit (newtrans);
|
||||
qof_event_gen (&newtrans->inst, QOF_EVENT_CREATE, NULL);
|
||||
LEAVE ("trans=%p %s", trans, trans->description);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* Reparent transaction to new book. This routine does this by
|
||||
* moving GncGUID's to the new book's entity tables.
|
||||
*/
|
||||
|
||||
void
|
||||
gnc_book_insert_trans (QofBook *book, Transaction *trans)
|
||||
{
|
||||
QofCollection *col;
|
||||
QofBook *trans_book;
|
||||
GList *node;
|
||||
|
||||
if (!trans || !book) return;
|
||||
|
||||
/* If this is the same book, its a no-op. */
|
||||
trans_book = qof_instance_get_book(trans);
|
||||
if (trans_book == book) return;
|
||||
|
||||
/* If the old and new book don't share backends, then clobber-copy;
|
||||
* i.e. destroy it in one backend, create it in another. */
|
||||
if (qof_book_get_backend(book) != qof_book_get_backend(trans_book))
|
||||
{
|
||||
gnc_book_insert_trans_clobber (book, trans);
|
||||
return;
|
||||
}
|
||||
ENTER ("trans=%p %s", trans, trans->description);
|
||||
|
||||
/* Fiddle the transaction into place in the new book */
|
||||
xaccTransBeginEdit (trans);
|
||||
|
||||
col = qof_book_get_collection (book, GNC_ID_TRANS);
|
||||
qof_instance_set_book(trans, book);
|
||||
qof_collection_insert_entity (col, &trans->inst);
|
||||
|
||||
col = qof_book_get_collection (book, GNC_ID_SPLIT);
|
||||
for (node = trans->splits; node; node = node->next)
|
||||
{
|
||||
Account *twin;
|
||||
Split *s = node->data;
|
||||
|
||||
/* Move the splits over (only if they haven't already been moved). */
|
||||
if (qof_instance_get_book(s) != book)
|
||||
{
|
||||
qof_instance_set_book(s, book);
|
||||
qof_collection_insert_entity (col, &s->inst);
|
||||
}
|
||||
|
||||
/* Find the twin account, and re-parent to that. */
|
||||
twin = xaccAccountLookupTwin (s->acc, book);
|
||||
if (!twin)
|
||||
{
|
||||
PERR ("near-fatal: twin account not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Move the split too, if it hasn't been moved already */
|
||||
if (s->acc != twin)
|
||||
{
|
||||
xaccAccountInsertSplit (twin, s);
|
||||
g_object_set(twin, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xaccTransCommitEdit (trans);
|
||||
qof_event_gen (&trans->inst, QOF_EVENT_MODIFY, NULL);
|
||||
LEAVE ("trans=%p %s", trans, trans->description);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* Reparent lot to new book. This routine does this by
|
||||
* completely deleting and recreating the lot.
|
||||
*/
|
||||
|
||||
void
|
||||
gnc_book_insert_lot_clobber (QofBook *book, GNCLot *lot)
|
||||
{
|
||||
PERR ("Not Implemented");
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* Reparent lot to new book. This routine does this by
|
||||
* moving GncGUID's to the new book's entity tables.
|
||||
*/
|
||||
|
||||
void
|
||||
gnc_book_insert_lot (QofBook *book, GNCLot *lot)
|
||||
{
|
||||
QofCollection *col;
|
||||
SplitList *snode;
|
||||
Account *twin;
|
||||
|
||||
if (!lot || !book) return;
|
||||
|
||||
/* If this is the same book, its a no-op. */
|
||||
if (gnc_lot_get_book(lot) == book) return;
|
||||
|
||||
if (qof_book_get_backend(book) !=
|
||||
qof_book_get_backend(gnc_lot_get_book(lot)))
|
||||
{
|
||||
gnc_book_insert_lot_clobber (book, lot);
|
||||
return;
|
||||
}
|
||||
ENTER ("lot=%p", lot);
|
||||
|
||||
col = qof_book_get_collection (book, GNC_ID_LOT);
|
||||
qof_instance_set_book(lot, book);
|
||||
qof_collection_insert_entity (col, QOF_INSTANCE(lot));
|
||||
|
||||
/* Move the splits over (only if they haven't already been moved). */
|
||||
col = qof_book_get_collection (book, GNC_ID_SPLIT);
|
||||
for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
|
||||
{
|
||||
Split *s = snode->data;
|
||||
if (qof_instance_get_book(s) != book)
|
||||
{
|
||||
qof_instance_set_book(s, book);
|
||||
qof_collection_insert_entity (col, &s->inst);
|
||||
}
|
||||
}
|
||||
|
||||
twin = xaccAccountLookupTwin (gnc_lot_get_account(lot), book);
|
||||
if (!twin)
|
||||
{
|
||||
PERR ("near-fatal: twin account not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
xaccAccountInsertLot (twin, lot);
|
||||
}
|
||||
LEAVE ("lot=%p", lot);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
void
|
||||
gnc_book_insert_price (QofBook *book, GNCPrice *pr)
|
||||
{
|
||||
QofCollection *col;
|
||||
QofBook *pr_book;
|
||||
|
||||
if (!pr || !book) return;
|
||||
|
||||
/* If this is the same book, its a no-op. */
|
||||
pr_book = qof_instance_get_book(pr);
|
||||
if (pr_book == book) return;
|
||||
|
||||
/* If the old and new book don't share backends, then clobber-copy;
|
||||
* i.e. destroy it in one backend, create it in another. */
|
||||
if (qof_book_get_backend(book) != qof_book_get_backend(pr_book))
|
||||
{
|
||||
gnc_book_insert_price_clobber (book, pr);
|
||||
return;
|
||||
}
|
||||
ENTER ("price=%p", pr);
|
||||
|
||||
/* Fiddle the price into place in the new book */
|
||||
gnc_price_ref (pr);
|
||||
gnc_price_begin_edit (pr);
|
||||
|
||||
col = qof_book_get_collection (book, GNC_ID_PRICE);
|
||||
qof_instance_set_book(pr, book);
|
||||
qof_collection_insert_entity (col, &pr->inst);
|
||||
|
||||
gnc_pricedb_remove_price (pr->db, pr);
|
||||
gnc_pricedb_add_price (gnc_pricedb_get_db (book), pr);
|
||||
|
||||
gnc_price_commit_edit (pr);
|
||||
gnc_price_unref (pr);
|
||||
|
||||
LEAVE ("price=%p", pr);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
void
|
||||
gnc_book_insert_price_clobber (QofBook *book, GNCPrice *pr)
|
||||
{
|
||||
PERR ("Not Implemented");
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* The following routines determine whether a given lot or
|
||||
* transaction is linked or related to another lot that is 'open'.
|
||||
* These return true if so.
|
||||
*
|
||||
* An 'open transaction' is a transaction that has a split
|
||||
* that belongs to an 'open lot'. An 'open lot' is one that
|
||||
* is not closed, OR ONE THAT HAS a split in it that belongs to
|
||||
* an open transaction.
|
||||
*
|
||||
* The need for this recursive definition is that some lots,
|
||||
* even though themselves closed, are participants in transactions
|
||||
* that cannot be moved to a closed book, and thus, by association
|
||||
* can't be moved either.
|
||||
*
|
||||
* Lots contain pointers to splits, and transactions contain
|
||||
* pointers to splits. Together, these form a graph, which may
|
||||
* be cyclic. We want to walk the entire graph, and determine
|
||||
* whether there are any open lots in it. The walk must be
|
||||
* recursive, and because it might be cyclic, we use a marker
|
||||
* to break the cycles.
|
||||
*/
|
||||
|
||||
static gboolean trans_has_open_lot_tree (Transaction *trans);
|
||||
static gboolean lot_has_open_trans_tree (GNCLot *lot);
|
||||
|
||||
static gboolean
|
||||
trans_has_open_lot_tree (Transaction *trans)
|
||||
{
|
||||
SplitList *split_list, *node;
|
||||
|
||||
if (1 == trans->marker) return FALSE;
|
||||
if (2 == trans->marker) return TRUE;
|
||||
trans->marker = 1;
|
||||
|
||||
split_list = xaccTransGetSplitList (trans);
|
||||
for (node = split_list; node; node = node->next)
|
||||
{
|
||||
Split *s = node->data;
|
||||
GNCLot *lot = s->lot;
|
||||
if (NULL == lot) continue;
|
||||
if ((FALSE == gnc_lot_is_closed(lot)) ||
|
||||
(lot_has_open_trans_tree (lot)))
|
||||
{
|
||||
trans->marker = 2;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
lot_has_open_trans_tree (GNCLot *lot)
|
||||
{
|
||||
SplitList *split_list, *snode;
|
||||
|
||||
if (1 == gnc_lot_get_marker(lot)) return FALSE;
|
||||
if (2 == gnc_lot_get_marker(lot)) return TRUE;
|
||||
gnc_lot_set_marker(lot, 1);
|
||||
|
||||
if (FALSE == gnc_lot_is_closed(lot))
|
||||
{
|
||||
gnc_lot_set_marker(lot, 2);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
split_list = gnc_lot_get_split_list (lot);
|
||||
for (snode = split_list; snode; snode = snode->next)
|
||||
{
|
||||
Split *s = snode->data;
|
||||
Transaction *trans = s->parent;
|
||||
if (trans_has_open_lot_tree (trans))
|
||||
{
|
||||
gnc_lot_set_marker(lot, 2);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* The following routines remove 'open lots' and 'open transactions'
|
||||
* from the lists passed in.
|
||||
*/
|
||||
|
||||
static LotList *
|
||||
lot_list_preen_open_lots (LotList *lot_list)
|
||||
{
|
||||
LotList *lnode;
|
||||
ENTER (" ");
|
||||
for (lnode = lot_list; lnode; )
|
||||
{
|
||||
GNCLot *lot = lnode->data;
|
||||
LotList *lnext = lnode->next;
|
||||
|
||||
if (lot_has_open_trans_tree (lot))
|
||||
lot_list = g_list_delete_link(lot_list, lnode);
|
||||
lnode = lnext;
|
||||
}
|
||||
LEAVE (" ");
|
||||
return lot_list;
|
||||
}
|
||||
|
||||
static TransList *
|
||||
trans_list_preen_open_lots (TransList *trans_list)
|
||||
{
|
||||
TransList *tnode;
|
||||
|
||||
ENTER (" ");
|
||||
for (tnode = trans_list; tnode; )
|
||||
{
|
||||
Transaction *trans = tnode->data;
|
||||
TransList *tnext = tnode->next;
|
||||
|
||||
if (trans_has_open_lot_tree (trans))
|
||||
{
|
||||
trans_list = g_list_remove_link (trans_list, tnode);
|
||||
/* XXX freeing this node somehow leads to glib g_list
|
||||
* memory corruption which later takes down the system.
|
||||
* I don't see why. */
|
||||
/* g_list_free_1 (tnode); */
|
||||
}
|
||||
tnode = tnext;
|
||||
}
|
||||
LEAVE (" ");
|
||||
return trans_list;
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* clear the markers for the above routines */
|
||||
|
||||
static void
|
||||
clear_markers (Account *account, gpointer dummy)
|
||||
{
|
||||
GList *lp;
|
||||
|
||||
if (!account) return;
|
||||
|
||||
for (lp = xaccAccountGetSplitList(account); lp; lp = lp->next)
|
||||
{
|
||||
Split *s = lp->data;
|
||||
Transaction *trans = s->parent;
|
||||
GNCLot *lot = s->lot;
|
||||
trans->marker = 0;
|
||||
if (lot) gnc_lot_set_marker(lot, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* Return a unique list of lots that are involved with the listed
|
||||
* transactions.
|
||||
*/
|
||||
|
||||
static LotList *
|
||||
create_lot_list_from_trans_list (TransList *trans_list)
|
||||
{
|
||||
LotList *lot_list = NULL;
|
||||
TransList *tnode;
|
||||
|
||||
for (tnode = trans_list; tnode; tnode = tnode->next)
|
||||
{
|
||||
Transaction *trans = tnode->data;
|
||||
SplitList *split_list = xaccTransGetSplitList (trans);
|
||||
SplitList *snode;
|
||||
for (snode = split_list; snode; snode = snode->next)
|
||||
{
|
||||
Split *s = snode->data;
|
||||
GNCLot *lot = xaccSplitGetLot(s);
|
||||
if (NULL == lot) continue;
|
||||
if (g_list_find (lot_list, lot)) continue;
|
||||
lot_list = g_list_prepend (lot_list, lot);
|
||||
}
|
||||
}
|
||||
return lot_list;
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
void
|
||||
gnc_book_partition_pricedb (QofBook *dest_book, QofBook *src_book, QofQuery *query)
|
||||
{
|
||||
GNCPriceDB *src_pdb, *dest_pdb;
|
||||
GList *price_list, *pnode;
|
||||
|
||||
if (!src_book || !dest_book || !query) return;
|
||||
ENTER (" src_book=%p dest_book=%p", src_book, dest_book);
|
||||
|
||||
src_pdb = gnc_pricedb_get_db (src_book);
|
||||
dest_pdb = gnc_pricedb_get_db (dest_book);
|
||||
|
||||
gnc_pricedb_begin_edit (src_pdb);
|
||||
gnc_pricedb_begin_edit (dest_pdb);
|
||||
gnc_pricedb_set_bulk_update (dest_pdb, TRUE);
|
||||
|
||||
qof_query_set_book (query, src_book);
|
||||
price_list = qof_query_run (query);
|
||||
|
||||
printf ("duude XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX prices\n");
|
||||
for (pnode = price_list; pnode; pnode = pnode->next)
|
||||
{
|
||||
GNCPrice *pr = pnode->data;
|
||||
gnc_book_insert_price (dest_book, pr);
|
||||
}
|
||||
|
||||
gnc_pricedb_set_bulk_update (dest_pdb, FALSE);
|
||||
gnc_pricedb_commit_edit (dest_pdb);
|
||||
gnc_pricedb_commit_edit (src_pdb);
|
||||
|
||||
LEAVE (" src_book=%p dest_book=%p", src_book, dest_book);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
void
|
||||
gnc_book_partition_txn (QofBook *dest_book, QofBook *src_book, QofQuery *query)
|
||||
{
|
||||
gnc_commodity_table *src_tbl, *dst_tbl;
|
||||
Account *src_root, *dst_root;
|
||||
time_t now;
|
||||
TransList *trans_list, *tnode;
|
||||
LotList *lot_list, *lnode;
|
||||
QofInstance *book_inst;
|
||||
|
||||
if (!src_book || !dest_book || !query) return;
|
||||
ENTER (" src_book=%p dest_book=%p", src_book, dest_book);
|
||||
|
||||
/* First, copy the book's KVP tree */
|
||||
/* hack alert -- FIXME -- this should really be a merge, not a
|
||||
* clobber copy, but I am too lazy to write a kvp merge routine,
|
||||
* and it is not needed for the current usage. */
|
||||
kvp_frame_delete (qof_book_get_slots(dest_book));
|
||||
book_inst = (QofInstance*)dest_book;
|
||||
book_inst->kvp_data = kvp_frame_copy (qof_book_get_slots(src_book));
|
||||
|
||||
/* Next, copy the commodity tables */
|
||||
src_tbl = gnc_commodity_table_get_table (src_book);
|
||||
dst_tbl = gnc_commodity_table_get_table (dest_book);
|
||||
gnc_commodity_table_copy (dst_tbl, src_tbl, dest_book);
|
||||
|
||||
/* Next, copy all of the accounts */
|
||||
/* hack alert -- FIXME -- this should really be a merge, not a
|
||||
* clobber copy, but I am too lazy to write an account-group merge
|
||||
* routine, and it is not needed for the current usage. */
|
||||
src_root = gnc_book_get_root_account (src_book);
|
||||
dst_root = gnc_book_get_root_account (dest_book);
|
||||
gnc_account_copy_children (dst_root, src_root);
|
||||
|
||||
/* Next, run the query */
|
||||
xaccAccountBeginEdit (dst_root);
|
||||
xaccAccountBeginEdit (src_root);
|
||||
qof_query_set_book (query, src_book);
|
||||
trans_list = qof_query_run (query);
|
||||
|
||||
/* Preen: remove open lots/ open trnasactions */
|
||||
gnc_account_foreach_descendant(src_root, clear_markers, NULL);
|
||||
trans_list = trans_list_preen_open_lots (trans_list);
|
||||
lot_list = create_lot_list_from_trans_list (trans_list);
|
||||
lot_list = lot_list_preen_open_lots (lot_list);
|
||||
|
||||
/* Move closed lots over to destination. Do this before moving
|
||||
* the txn's, so that the lots don't get trashed. */
|
||||
for (lnode = lot_list; lnode; lnode = lnode->next)
|
||||
{
|
||||
GNCLot *lot = lnode->data;
|
||||
gnc_book_insert_lot (dest_book, lot);
|
||||
}
|
||||
|
||||
/* Move the transactions over to the destination book. */
|
||||
for (tnode = trans_list; tnode; tnode = tnode->next)
|
||||
{
|
||||
Transaction *trans = tnode->data;
|
||||
gnc_book_insert_trans (dest_book, trans);
|
||||
}
|
||||
|
||||
xaccAccountCommitEdit (src_root);
|
||||
xaccAccountCommitEdit (dst_root);
|
||||
|
||||
/* Make note of the sibling books */
|
||||
now = time(0);
|
||||
gnc_kvp_bag_add (qof_book_get_slots(src_book), "gemini", now,
|
||||
"book_guid", qof_book_get_guid(dest_book),
|
||||
NULL);
|
||||
gnc_kvp_bag_add (qof_book_get_slots(dest_book), "gemini", now,
|
||||
"book_guid", qof_book_get_guid(src_book),
|
||||
NULL);
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* Find nearest equity account */
|
||||
|
||||
static Account *
|
||||
find_nearest_equity_acct (Account *acc)
|
||||
{
|
||||
QofBook *book;
|
||||
GList *acc_list, *node;
|
||||
Account *parent, *root, *candidate;
|
||||
|
||||
parent = gnc_account_get_parent (acc);
|
||||
g_return_val_if_fail (parent, NULL);
|
||||
|
||||
/* See if we can find an equity account that is peered to this
|
||||
* account. If not, check succssively higher levels. */
|
||||
while (parent != NULL)
|
||||
{
|
||||
acc_list = gnc_account_get_children(parent);
|
||||
for (node = acc_list; node; node = node->next)
|
||||
{
|
||||
candidate = (Account *) node->data;
|
||||
if ((ACCT_TYPE_EQUITY == xaccAccountGetType (candidate)) &&
|
||||
gnc_commodity_equiv(xaccAccountGetCommodity(acc),
|
||||
xaccAccountGetCommodity(candidate)))
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
g_list_free(acc_list);
|
||||
parent = gnc_account_get_parent (parent);
|
||||
}
|
||||
|
||||
/* If we got to here, then we are at the root account, and there is no
|
||||
* equity account to be found. So we need to create one. */
|
||||
|
||||
book = gnc_account_get_book(acc);
|
||||
root = gnc_book_get_root_account(book);
|
||||
candidate = xaccMallocAccount (book);
|
||||
xaccAccountBeginEdit (candidate);
|
||||
gnc_account_append_child (root, candidate);
|
||||
xaccAccountSetType (candidate, ACCT_TYPE_EQUITY);
|
||||
xaccAccountSetName (candidate, xaccAccountGetTypeStr(ACCT_TYPE_EQUITY));
|
||||
xaccAccountSetCommodity (candidate, xaccAccountGetCommodity(acc));
|
||||
xaccAccountCommitEdit (candidate);
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* Traverse all accounts, get account balances */
|
||||
|
||||
static void
|
||||
add_closing_balances (Account *parent,
|
||||
QofBook *open_book,
|
||||
QofBook *closed_book,
|
||||
Account *equity_account,
|
||||
Timespec *post_date, Timespec *date_entered,
|
||||
const char *desc)
|
||||
{
|
||||
GList *acc_list, *node;
|
||||
|
||||
if (!parent) return;
|
||||
|
||||
ENTER (" enter=%s post=%s desc=%s", gnc_print_date(*date_entered),
|
||||
gnc_print_date (*post_date), desc);
|
||||
xaccAccountBeginEdit (equity_account);
|
||||
|
||||
/* Walk accounts in closed book */
|
||||
acc_list = gnc_account_get_children(parent);
|
||||
for (node = acc_list; node; node = node->next)
|
||||
{
|
||||
KvpFrame *cwd;
|
||||
Account *twin;
|
||||
Account * candidate = (Account *) node->data;
|
||||
GNCAccountType tip = xaccAccountGetType (candidate);
|
||||
|
||||
/* Find the peer account of this account in the open book */
|
||||
twin = xaccAccountLookupTwin (candidate, open_book);
|
||||
|
||||
/* -------------------------------- */
|
||||
/* Add KVP to open account, indicating the progenitor
|
||||
* of this account. */
|
||||
xaccAccountBeginEdit (twin);
|
||||
cwd = xaccAccountGetSlots (twin);
|
||||
kvp_frame_set_guid (cwd, "/book/prev-acct", qof_entity_get_guid (QOF_INSTANCE(candidate)));
|
||||
kvp_frame_set_guid (cwd, "/book/prev-book", qof_book_get_guid(closed_book));
|
||||
|
||||
qof_instance_set_slots(QOF_INSTANCE(twin), twin->inst.kvp_data);
|
||||
|
||||
/* -------------------------------- */
|
||||
/* Add KVP to closed account, indicating where
|
||||
* the next book is. */
|
||||
xaccAccountBeginEdit (candidate);
|
||||
cwd = xaccAccountGetSlots (candidate);
|
||||
kvp_frame_set_guid (cwd, "/book/next-book", qof_book_get_guid(open_book));
|
||||
kvp_frame_set_guid (cwd, "/book/next-acct", qof_entity_get_guid (QOF_INSTANCE(twin)));
|
||||
|
||||
qof_instance_set_slots(QOF_INSTANCE(candidate), candidate->inst.kvp_data);
|
||||
|
||||
/* -------------------------------- */
|
||||
/* We need to carry a balance on any account that is not
|
||||
* and income or expense or equity account */
|
||||
if ((ACCT_TYPE_INCOME != tip) && (ACCT_TYPE_EXPENSE != tip) &&
|
||||
(ACCT_TYPE_EQUITY != tip && ACCT_TYPE_TRADING != tip))
|
||||
{
|
||||
gnc_numeric baln;
|
||||
baln = xaccAccountGetBalance (candidate);
|
||||
|
||||
/* Don't bother with creating the equity balance if its zero */
|
||||
if (FALSE == gnc_numeric_zero_p(baln))
|
||||
{
|
||||
Split *se, *st;
|
||||
Transaction *trans;
|
||||
Account *equity;
|
||||
|
||||
/* Find the equity account into which we'll poke the
|
||||
* balancing transaction */
|
||||
if (NULL == equity_account)
|
||||
{
|
||||
equity = find_nearest_equity_acct (twin);
|
||||
xaccAccountBeginEdit (equity);
|
||||
}
|
||||
else
|
||||
{
|
||||
equity = equity_account;
|
||||
}
|
||||
|
||||
/* -------------------------------- */
|
||||
/* Create the balancing transaction */
|
||||
trans = xaccMallocTransaction (open_book);
|
||||
xaccTransBeginEdit (trans);
|
||||
|
||||
xaccTransSetDatePostedTS (trans, post_date);
|
||||
xaccTransSetDateEnteredTS (trans, date_entered);
|
||||
xaccTransSetDescription (trans, desc);
|
||||
xaccTransSetCurrency (trans, xaccAccountGetCommodity(equity));
|
||||
|
||||
st = xaccMallocSplit(open_book);
|
||||
xaccTransAppendSplit(trans, st);
|
||||
xaccAccountInsertSplit (twin, st);
|
||||
|
||||
se = xaccMallocSplit(open_book);
|
||||
xaccTransAppendSplit(trans, se);
|
||||
xaccAccountInsertSplit (equity, se);
|
||||
|
||||
xaccSplitSetAmount (st, baln);
|
||||
xaccSplitSetValue (st, baln);
|
||||
xaccSplitSetAmount (se, gnc_numeric_neg(baln));
|
||||
xaccSplitSetValue (se, gnc_numeric_neg(baln));
|
||||
|
||||
/* Add KVP data showing where the balancing
|
||||
* transaction came from */
|
||||
cwd = xaccTransGetSlots (trans);
|
||||
kvp_frame_set_guid (cwd, "/book/closed-book", qof_book_get_guid(closed_book));
|
||||
kvp_frame_set_guid (cwd, "/book/closed-acct", qof_entity_get_guid(QOF_INSTANCE(candidate)));
|
||||
|
||||
xaccTransCommitEdit (trans);
|
||||
|
||||
if (NULL == equity_account)
|
||||
{
|
||||
xaccAccountCommitEdit (equity);
|
||||
}
|
||||
/* -------------------------------- */
|
||||
/* Add KVP to closed account, indicating where the
|
||||
* balance was carried forward to. */
|
||||
cwd = xaccAccountGetSlots (candidate);
|
||||
kvp_frame_set_guid (cwd, "/book/balancing-trans", xaccTransGetGUID(trans));
|
||||
}
|
||||
}
|
||||
|
||||
/* We left an open dangling above ... */
|
||||
xaccAccountCommitEdit (candidate);
|
||||
xaccAccountCommitEdit (twin);
|
||||
|
||||
/* Recurse down to the children */
|
||||
if (gnc_account_n_children(candidate) > 0)
|
||||
{
|
||||
PINFO ("add closing baln to subaccts of %s",
|
||||
xaccAccountGetDescription(candidate));
|
||||
add_closing_balances (candidate, open_book, closed_book,
|
||||
equity_account,
|
||||
post_date, date_entered, desc);
|
||||
}
|
||||
}
|
||||
g_list_free(acc_list);
|
||||
xaccAccountCommitEdit (equity_account);
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
static void
|
||||
period_begin_edit (QofBook *src_book, QofBook *dest_book)
|
||||
{
|
||||
/*
|
||||
QofBackend *be;
|
||||
be = qof_book_get_backend(src_book);
|
||||
if (be && be->begin)
|
||||
{
|
||||
// (*be->begin)(be, GNC_ID_PERIOD, dest_book);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
period_commit_edit (QofBook *src_book, QofBook *dest_book)
|
||||
{
|
||||
/*
|
||||
QofBackend *be;
|
||||
be = qof_book_get_backend(src_book);
|
||||
if (be && be->commit)
|
||||
{
|
||||
// (*be->commit)(be, GNC_ID_PERIOD, dest_book);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
/* Split a book into two by date */
|
||||
|
||||
QofBook *
|
||||
gnc_book_close_period (QofBook *existing_book, Timespec calve_date,
|
||||
Account *equity_account,
|
||||
const char * memo)
|
||||
{
|
||||
QofQuery *txn_query, *prc_query;
|
||||
QofQueryPredData *pred_data;
|
||||
GSList *param_list;
|
||||
QofBook *closing_book;
|
||||
KvpFrame *exist_cwd, *partn_cwd;
|
||||
Timespec ts;
|
||||
|
||||
if (!existing_book) return NULL;
|
||||
ENTER (" date=%s memo=%s", gnc_print_date(calve_date), memo);
|
||||
|
||||
/* Setup closing book */
|
||||
closing_book = qof_book_new();
|
||||
qof_book_set_backend (closing_book, qof_book_get_backend(existing_book));
|
||||
qof_book_mark_closed(closing_book);
|
||||
|
||||
period_begin_edit (existing_book, closing_book);
|
||||
|
||||
/* Get all transactions that are *earlier* than the calve date,
|
||||
* and put them in the new book. */
|
||||
txn_query = qof_query_create_for (GNC_ID_TRANS);
|
||||
pred_data = qof_query_date_predicate (QOF_COMPARE_LTE,
|
||||
QOF_DATE_MATCH_NORMAL,
|
||||
calve_date);
|
||||
param_list = qof_query_build_param_list (TRANS_DATE_POSTED, NULL);
|
||||
qof_query_add_term (txn_query, param_list, pred_data, QOF_QUERY_FIRST_TERM);
|
||||
|
||||
gnc_book_partition_txn (closing_book, existing_book, txn_query);
|
||||
qof_query_destroy (txn_query);
|
||||
|
||||
/* Move prices over too */
|
||||
prc_query = qof_query_create_for (GNC_ID_PRICE);
|
||||
pred_data = qof_query_date_predicate (QOF_COMPARE_LTE,
|
||||
QOF_DATE_MATCH_NORMAL,
|
||||
calve_date);
|
||||
param_list = qof_query_build_param_list (PRICE_DATE, NULL);
|
||||
qof_query_add_term (prc_query, param_list, pred_data, QOF_QUERY_FIRST_TERM);
|
||||
|
||||
gnc_book_partition_pricedb (closing_book, existing_book, prc_query);
|
||||
qof_query_destroy (prc_query);
|
||||
|
||||
/* Now add the various identifying kvp's */
|
||||
/* cwd == 'current working directory' */
|
||||
exist_cwd = qof_book_get_slots(existing_book);
|
||||
partn_cwd = qof_book_get_slots(closing_book);
|
||||
|
||||
/* Mark the boundary date between the books */
|
||||
kvp_frame_set_timespec (exist_cwd, "/book/open-date", calve_date);
|
||||
kvp_frame_set_timespec (partn_cwd, "/book/close-date", calve_date);
|
||||
|
||||
/* Mark partition as being closed */
|
||||
ts.tv_sec = time(0);
|
||||
ts.tv_nsec = 0;
|
||||
kvp_frame_set_timespec (partn_cwd, "/book/log-date", ts);
|
||||
|
||||
/* Set up pointers to each book from the other. */
|
||||
kvp_frame_set_guid (partn_cwd, "/book/next-book", qof_book_get_guid(existing_book));
|
||||
kvp_frame_set_guid (exist_cwd, "/book/prev-book", qof_book_get_guid(closing_book));
|
||||
|
||||
/* add in transactions to equity accounts that will
|
||||
* hold the colsing balances */
|
||||
add_closing_balances (gnc_book_get_root_account(closing_book),
|
||||
existing_book, closing_book,
|
||||
equity_account,
|
||||
&calve_date, &ts, memo);
|
||||
|
||||
period_commit_edit (existing_book, closing_book);
|
||||
|
||||
LEAVE (" ");
|
||||
return closing_book;
|
||||
}
|
||||
|
||||
/* ============================= END OF FILE ====================== */
|
||||
@@ -1,188 +0,0 @@
|
||||
/********************************************************************\
|
||||
* Period.h -- Implement accounting Periods *
|
||||
* *
|
||||
* 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@gnu.org *
|
||||
\********************************************************************/
|
||||
/** @addtogroup Engine
|
||||
@{ */
|
||||
/** @addtogroup Period Accounting Periods
|
||||
The architecture of the Accounting Period design is discussed
|
||||
in greater detail in the file "src/doc/books.txt"
|
||||
@{ */
|
||||
/** @file Period.h
|
||||
* @brief Implement accounting periods, as per design in src/doc/books.txt
|
||||
* @author Copyright (c) 2001,2003 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef XACC_PERIOD_H
|
||||
#define XACC_PERIOD_H
|
||||
|
||||
#include "gnc-engine.h"
|
||||
|
||||
|
||||
/** The gnc_book_close_period() routine will 'close' a book at
|
||||
* the indicated date. It returns a pointer to the closed book,
|
||||
* while the argument remains open. This routine will move
|
||||
* all of the older transactions from the open book to the
|
||||
* closed book. The guid's of the old transactions will not
|
||||
* be changed in the move. Note, however, that the closed
|
||||
* book will have a copy of every account in the open book,
|
||||
* and that these copies will have new GncGUID's issued to them.
|
||||
* Thus, every account has a 'twin' in the other book.
|
||||
*
|
||||
* This routine will also create 'equity transactions' in
|
||||
* order to preserve the balances on accounts. For any
|
||||
* account that is not of income, expense, trading or equity type,
|
||||
* this routine wil find the closing balance of each account
|
||||
* in the closed book. It will then create an 'equity
|
||||
* transaction' in the open book, creating an opening balance
|
||||
* between an equity account and the twin account to the
|
||||
* closed account. The 'memo' field will be used to set
|
||||
* the description in the equity transaction. Typically,
|
||||
* you will want to set this field to _("Opening Balance").
|
||||
*
|
||||
* The equity_account argument is supposed to indicate the
|
||||
* equity account in the open book into which the opening
|
||||
* balances will be placed. This argument may be NULL,
|
||||
* if it is NULL, then a search algorithm will be used to
|
||||
* find a suitable equity account. If NULL, this routine
|
||||
* searches for the 'nearest' account of GNCAccountType ACCT_TYPE_EQUITY
|
||||
* among its siblings, or the siblings of its parents. It
|
||||
* does not search downwards. If it does not find such an
|
||||
* account, it will create one, hanging off the top-most group.
|
||||
*
|
||||
* This routine also populates a number of KVP values in
|
||||
* order to make a log of the closing. In principle, the
|
||||
* stored KVP's should be enough to locate everything needed
|
||||
* to safely re-open and re-close a closed book. In particular,
|
||||
* if a closed book is re-opened, the 'equity transaction'
|
||||
* would need to be adjusted.
|
||||
*
|
||||
* The kvp values that are set are:
|
||||
*
|
||||
* Implemented in the closed book:
|
||||
* /book/close-date Latest date in this book. Must not change.
|
||||
* /book/log-date Date on which user called this routine.
|
||||
* /book/next-book GncGUID of next book (the still-open book).
|
||||
*
|
||||
* Implemented in still-open book:
|
||||
* /book/open-date Earliest date in this book.
|
||||
* /book/prev-book GncGUID of previous book (the closed book).
|
||||
*
|
||||
* Implemented in the balancing transaction:
|
||||
* /book/closed-acct GncGUID of account whose balance was brought forward
|
||||
* /book/closed-book GncGUID of book whose balance was brought forward
|
||||
*
|
||||
* Implemented in the closed account:
|
||||
* /book/balancing-trans GncGUID of equity-balancing transaction.
|
||||
* /book/next-book GncGUID of equity-balancing book.
|
||||
* /book/next-acct GncGUID of twin of this account in the open book.
|
||||
*
|
||||
* Implemented in the still-open account:
|
||||
* /book/prev-acct GncGUID of twin of this account in the closed book.
|
||||
* /book/prev-book GncGUID of previous book (the closed book)
|
||||
*
|
||||
*/
|
||||
QofBook * gnc_book_close_period (QofBook *, Timespec,
|
||||
Account *equity_acct,
|
||||
const char *memo);
|
||||
|
||||
/** The gnc_book_partition_txn() uses the result of the indicated query
|
||||
* to move a set of transactions from the "src" book to the "dest"
|
||||
* book. Before moving the transactions, it will first place a
|
||||
* copy of all of the accounts in "src" into "dest". This is done
|
||||
* in order to ensure that all of the moved transactions will have
|
||||
* the corrrect set of accounts to reference. The transactions
|
||||
* that will be moved are precisely those specified by the query.
|
||||
* Any query that returns a list of transactions will work to
|
||||
* partition a book; however, its expected that this routine will
|
||||
* mostly serve as a utility to break up a book into accounting
|
||||
* periods.
|
||||
*
|
||||
* This routine intentionally does not copy scheduled/recurring
|
||||
* transactions.
|
||||
*
|
||||
* This routine will also copy closed lots to the destination book.
|
||||
* NOTICE:
|
||||
* It will not copy open lots, nor will it copy lots that have
|
||||
* lead to transactions that contains splits in other open lots.
|
||||
* Leaving behind open lots is exactly what is needed for closing
|
||||
* books, but it means that gnc_book_partition() is not really
|
||||
* a 'general purpose' function. The way to fix this would be to
|
||||
* weed out open lots by constructing the query correctly.
|
||||
*
|
||||
* When an account is copied, the copy is issued a new GncGUID.
|
||||
* The GncGUID of its sibling is placed in the 'gemini' KVP value
|
||||
* (See kvp_doc.txt for more detail). Transactions and splits
|
||||
* are moved without reassigning them a new GncGUID. Note they
|
||||
* are removed from one book's entity table and placed into the
|
||||
* other book: Once moved, they won't be findable in the entity
|
||||
* table of the old book.
|
||||
*
|
||||
* Known Bugs:
|
||||
* When this routine copies accounts, it does not check to see
|
||||
* if they already exist in the 'dest' book; it should.
|
||||
* For the current usage, this bug aint important, and I'm too
|
||||
* lazy to fix it.
|
||||
*/
|
||||
void gnc_book_partition_txn (QofBook *dest, QofBook *src, QofQuery *);
|
||||
|
||||
/** The gnc_book_partition_pricedb() routine uses te result of the
|
||||
* indicated query to move a set of prices from the "src" book
|
||||
* to the "dest" book. The query passed into it must be set up
|
||||
* to return a list of prices.
|
||||
*/
|
||||
void gnc_book_partition_pricedb (QofBook *dest, QofBook *src, QofQuery *);
|
||||
|
||||
/** The gnc_book_insert_trans_clobber() routine takes an existing
|
||||
* transaction that is located in one book, and moves it to
|
||||
* another book. It moves all of the splits as well. In the
|
||||
* course of the move, the transaction is literally deleted
|
||||
* from the first book as its placed into the second. The
|
||||
* transaction and split GncGUID's are not changed in the move.
|
||||
* This routine assumes that twin accounts already exist in
|
||||
* both books (and can be located with the standard twining
|
||||
* proceedure).
|
||||
*
|
||||
* Note that this routine does *not* move the lots that any
|
||||
* of the splits might belong to. These must be moved sepearately.
|
||||
* Note that one must take care when moving a transaction, so
|
||||
* that any associated lots don't end up hamstrung across two
|
||||
* different books.
|
||||
*
|
||||
* The gnc_book_insert_trans() routine does the same as the above,
|
||||
* except that it doesn't actually clobber the transaction: it
|
||||
* merely moves the transaction and split GncGUID's to the new
|
||||
* books' entity tables, and not much else.
|
||||
*
|
||||
* The gnc_book_insert_lot() routine, as above, but for lots ...
|
||||
*/
|
||||
|
||||
void gnc_book_insert_trans (QofBook *book, Transaction *trans);
|
||||
void gnc_book_insert_trans_clobber (QofBook *book, Transaction *trans);
|
||||
|
||||
void gnc_book_insert_lot (QofBook *book, GNCLot *lot);
|
||||
void gnc_book_insert_lot_clobber (QofBook *book, GNCLot *lot);
|
||||
|
||||
void gnc_book_insert_price (QofBook *book, GNCPrice *prc);
|
||||
void gnc_book_insert_price_clobber (QofBook *book, GNCPrice *prc);
|
||||
|
||||
#endif /* XACC_PERIOD_H */
|
||||
/** @} */
|
||||
/** @} */
|
||||
@@ -35,7 +35,6 @@ TESTS = \
|
||||
test-account-object \
|
||||
test-group-vs-book \
|
||||
test-lots \
|
||||
test-period \
|
||||
test-querynew \
|
||||
test-query \
|
||||
test-split-vs-account \
|
||||
@@ -66,7 +65,6 @@ check_PROGRAMS = \
|
||||
test-account-object \
|
||||
test-group-vs-book \
|
||||
test-load-engine \
|
||||
test-period \
|
||||
test-lots \
|
||||
test-numeric \
|
||||
test-object \
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/***************************************************************************
|
||||
* test-period.c
|
||||
*
|
||||
* December 2001
|
||||
* Copyright 2001 Linas Vepstas <linas@linas.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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
/*
|
||||
* Minimal test to see if a book can be split into two periods
|
||||
* without crashing.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
#include <glib.h>
|
||||
#include "qof.h"
|
||||
#include <time.h>
|
||||
#include "cashobjects.h"
|
||||
#include "Account.h"
|
||||
#include "Period.h"
|
||||
#include "test-stuff.h"
|
||||
#include "test-engine-stuff.h"
|
||||
#include "Transaction.h"
|
||||
|
||||
static int num_trans = 0;
|
||||
static void
|
||||
run_test (void)
|
||||
{
|
||||
QofSession *sess1, *sess2;
|
||||
QofBook *openbook, *closedbook;
|
||||
GList *acclist, *anode;
|
||||
Account *root, *acc, *equity;
|
||||
SplitList *splist;
|
||||
Split *sfirst, *slast;
|
||||
Transaction *tfirst, *tlast;
|
||||
Timespec tsfirst, tslast, tsmiddle;
|
||||
|
||||
sess1 = get_random_session ();
|
||||
openbook = qof_session_get_book (sess1);
|
||||
sess2 = get_random_session ();
|
||||
closedbook = qof_session_get_book(sess2);
|
||||
acc = NULL;
|
||||
equity = get_random_account(openbook);
|
||||
if (!openbook)
|
||||
{
|
||||
failure("book not created");
|
||||
exit(get_rv());
|
||||
}
|
||||
|
||||
add_random_transactions_to_book (openbook, num_trans);
|
||||
|
||||
root = gnc_book_get_root_account (openbook);
|
||||
|
||||
acclist = gnc_account_get_descendants (root);
|
||||
for (anode = acclist; anode; anode = anode->next)
|
||||
{
|
||||
int ns;
|
||||
acc = anode->data;
|
||||
ns = g_list_length (xaccAccountGetSplitList (acc));
|
||||
if (2 <= ns) break;
|
||||
acc = NULL;
|
||||
}
|
||||
g_list_free(acclist);
|
||||
|
||||
if (!acc)
|
||||
{
|
||||
failure("book didn't have accounts with enough splits");
|
||||
exit(get_rv());
|
||||
}
|
||||
|
||||
splist = xaccAccountGetSplitList(acc);
|
||||
if (!splist)
|
||||
{
|
||||
failure("account has no transactions");
|
||||
exit(get_rv());
|
||||
}
|
||||
|
||||
sfirst = splist->data;
|
||||
slast = g_list_last(splist) ->data;
|
||||
if (sfirst == slast)
|
||||
{
|
||||
failure("account doesn't have enough transactions");
|
||||
exit(get_rv());
|
||||
}
|
||||
|
||||
tfirst = xaccSplitGetParent (sfirst);
|
||||
tlast = xaccSplitGetParent (slast);
|
||||
|
||||
if (!tfirst || !tlast)
|
||||
{
|
||||
failure("malformed transactions in account");
|
||||
exit(get_rv());
|
||||
}
|
||||
|
||||
tsfirst = xaccTransRetDatePostedTS (tfirst);
|
||||
tslast = xaccTransRetDatePostedTS (tlast);
|
||||
|
||||
if (tsfirst.tv_sec == tslast.tv_sec)
|
||||
{
|
||||
failure("transactions not time separated");
|
||||
exit(get_rv());
|
||||
}
|
||||
|
||||
tsmiddle = tsfirst;
|
||||
tsmiddle.tv_sec = (tsfirst.tv_sec + tslast.tv_sec) / 2;
|
||||
closedbook = gnc_book_close_period (openbook, tsmiddle,
|
||||
equity, "this is opening balance dude");
|
||||
|
||||
if (!closedbook)
|
||||
{
|
||||
failure("closed book not created");
|
||||
exit(get_rv());
|
||||
}
|
||||
|
||||
success ("periods lightly tested and seem to work");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
if (argc == 2)
|
||||
num_trans = atoi(argv[1]);
|
||||
else num_trans = 120;
|
||||
|
||||
qof_init();
|
||||
g_log_set_always_fatal( G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING );
|
||||
|
||||
if (cashobjects_register())
|
||||
{
|
||||
srand(num_trans);
|
||||
run_test ();
|
||||
print_test_results();
|
||||
}
|
||||
qof_close();
|
||||
return get_rv();
|
||||
}
|
||||
@@ -38,7 +38,6 @@
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "Recurrence.h"
|
||||
#include "Period.h"
|
||||
#include "Query.h"
|
||||
#include "Scrub.h"
|
||||
#include "Scrub3.h"
|
||||
@@ -57,7 +56,6 @@
|
||||
#include "gnc-session.h"
|
||||
|
||||
#define ASSISTANT_ACCT_PERIOD_CM_CLASS "assistant-acct-period"
|
||||
/*#define REALLY_DO_CLOSE_BOOKS */
|
||||
|
||||
static QofLogModule log_module = GNC_MOD_ASSISTANT;
|
||||
|
||||
@@ -479,7 +477,6 @@ ap_assistant_finish (GtkAssistant *assistant, gpointer user_data)
|
||||
char *bnotes;
|
||||
Timespec closing_date;
|
||||
KvpFrame *book_frame;
|
||||
gboolean really_do_close_books = FALSE;
|
||||
|
||||
ENTER("info=%p", info);
|
||||
|
||||
@@ -496,35 +493,6 @@ ap_assistant_finish (GtkAssistant *assistant, gpointer user_data)
|
||||
|
||||
timespecFromTime_t (&closing_date,
|
||||
gnc_timet_get_day_end_gdate (&info->closing_date));
|
||||
|
||||
#ifdef REALLY_DO_CLOSE_BOOKS
|
||||
really_do_close_books = TRUE;
|
||||
#endif /* REALLY_DO_CLOSE_BOOKS */
|
||||
|
||||
if (really_do_close_books)
|
||||
{
|
||||
/* Close the books ! */
|
||||
qof_event_suspend ();
|
||||
gnc_suspend_gui_refresh ();
|
||||
|
||||
scrub_all();
|
||||
closed_book = gnc_book_close_period (current_book, closing_date, NULL, btitle);
|
||||
|
||||
book_frame = qof_book_get_slots(closed_book);
|
||||
kvp_frame_set_str (book_frame, "/book/title", btitle);
|
||||
kvp_frame_set_str (book_frame, "/book/notes", bnotes);
|
||||
|
||||
qof_session_add_book (gnc_get_current_session(), closed_book);
|
||||
|
||||
/* We must save now; if we don't, and the user bails without saving,
|
||||
* then opening account balances will be incorrect, and this can only
|
||||
* lead to unhappiness.
|
||||
*/
|
||||
gnc_file_save ();
|
||||
gnc_resume_gui_refresh ();
|
||||
qof_event_resume ();
|
||||
gnc_gui_refresh_all (); /* resume above should have been enough ??? */
|
||||
}
|
||||
g_free(bnotes);
|
||||
|
||||
/* Report the status back to the user. */
|
||||
|
||||
Reference in New Issue
Block a user