GnuCash  5.5-60-g698cc23051+
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Transaction.c
1 /********************************************************************\
2  * Transaction.c -- transaction implementation *
3  * Copyright (C) 1997 Robin D. Clark *
4  * Copyright (C) 1997-2003 Linas Vepstas <linas@linas.org> *
5  * Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
6  * Copyright (c) 2006 David Hampton <hampton@employees.org> *
7  * *
8  * This program is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU General Public License as *
10  * published by the Free Software Foundation; either version 2 of *
11  * the License, or (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License*
19  * along with this program; if not, contact: *
20  * *
21  * Free Software Foundation Voice: +1-617-542-5942 *
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23  * Boston, MA 02110-1301, USA gnu@gnu.org *
24  * *
25 \********************************************************************/
26 
27 #include <config.h>
28 
29 #include <platform.h>
30 #if PLATFORM(WINDOWS)
31 #include <windows.h>
32 #endif
33 
34 #include <glib.h>
35 #include <glib/gi18n.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdint.h>
39 #include <time.h>
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 
44 #include "AccountP.h"
45 #include "Scrub.h"
46 #include "Scrub3.h"
47 #include "TransactionP.h"
48 #include "SplitP.h"
49 #include "TransLog.h"
50 #include "cap-gains.h"
51 #include "gnc-commodity.h"
52 #include "gnc-engine.h"
53 #include "gnc-lot.h"
54 #include "gnc-event.h"
55 #include <gnc-date.h>
56 #include "SchedXaction.h"
57 #include "gncBusiness.h"
58 #include <qofinstance-p.h>
59 #include "gncInvoice.h"
60 #include "gncOwner.h"
61 
62 /* Notes about xaccTransBeginEdit(), xaccTransCommitEdit(), and
63  * xaccTransRollback():
64  *
65  * Why use it:
66  *
67  * Data consistency: Wrapping your changes to financial data inside
68  * a BeginEdit/CommitEdit block allows the engine to verify that
69  * your changes still leave the financial objects in an internally
70  * consistent state. This is true even though you may make a series
71  * of individual changes that are not consistent by themselves. In
72  * this way, it's like telling the engine, "Okay, I've finished my
73  * edits. Please check my work."
74  *
75  * Data integrity: The other benefit of the BeginEdit/CommitEdit
76  * block is that it allows the engine (and the backend) to remember
77  * the last known correct state of your data. This allows you to
78  * undo any changes that you don't want to keep. In this way, it's
79  * like telling the engine telling the back end, "Yes, I really mean
80  * it. Remember this data." or "Nevermind, scratch that." The
81  * important feature here is that if things go bad, for whatever
82  * reason (e.g. the application crashed, you lost the backend), your
83  * data remains in the state it was in just after the previous
84  * xaccTransCommitEdit(). [assuming no nesting, which probably
85  * isn't useful outside the engine.]
86  *
87  * Note that the backend doesn't care about data consistency -
88  * that's the engine's job.
89  *
90  * Example Use:
91  *
92  * xaccTransBeginEdit(trans);
93  *
94  *
95  * split = xaccMallocSplit(book);
96  * xaccSplitSetAccount(split, acc);
97  * xaccSplitSetParent(split, trans); // Adding a new split
98  *
99  * xaccSplitSetValue(split, val); // Changing a split
100  *
101  * xaccSplitDestroy(split); // Removing a split
102  *
103  * xaccTransSetNum(trans, "501"); // Changing the trans
104  *
105  * if (really_do_it)
106  * xaccTransCommitEdit(trans);
107  * else
108  * xaccTransRollbackEdit(trans);
109  *
110  * How it works:
111  *
112  * Calling xaccTransBeginEdit() starts a BeginEdit/CommitEdit block.
113  * Inside the block any changes to the transaction or any splits in
114  * the transaction are considered "pending". What does that mean?
115  *
116  * In general that means that if you set and then get the
117  * transaction's or split's parameters inside the
118  * BeginEdit/CommitEdit block, you'll get the values you just set.
119  * However, if you change an object's many-to-one relationship with
120  * another object, you won't see the change from the "many" side
121  * until the CommitEdit. For example, if you move a split from one
122  * account into another, you can see the change with
123  * xaccSplitGetAccount(), but both Accounts' split lists won't be
124  * updated until the CommitEdit. Correspondingly, no signals
125  * (events) will be generated for those "foreign" objects, or the
126  * Transaction, until the CommitEdit.
127  *
128  * This behavior is important because, when we're finally ready to
129  * commit to the backend, we can't be 100% sure that the backend
130  * will still be available. We have to offer the backend all of the
131  * new state as if it were already "true", but we need to save all of
132  * the old state in case the backend won't accept our commit. If
133  * the backend commit fails, we have to restore all the old state.
134  * If the backend commit succeeds, and *only* after it succeeds, we
135  * can advertise the new state to the rest of the engine (and gui).
136  *
137  * Q: Who owns the ref of an added split if the Transaction is rolled
138  * back?
139  *
140  * A: This is a design decision. If the answer is 'the user',
141  * then the burden is on the api user to check the transaction after
142  * every commit to see if the added split is really in the
143  * transaction. If they don't they risk leaking the split if the
144  * commit was rolled back. Another design is to answer 'the engine'.
145  * In that case the burden is on the engine to free a newly added
146  * split if the commit is rolled back. Unfortunately the engine
147  * objects aren't ref-counted, so this is tricky.
148  *
149  * In the current implementation, the answer is 'the engine', but
150  * that means that you must not add the split to two different
151  * transactions during the begin/commit block, because if one rolls
152  * back, they will both think they own the split. This is one
153  * specific example of the general problem that the outcome of two
154  * parallel begin/commit edit blocks for two transactions where edits
155  * for both transactions involve the same splits and one or more
156  * edit-blocks is rolled-back, is poorly-defined.
157  *
158  *
159  *
160  * Design notes on event-generation: transaction-modified-events
161  * should not be generated until transaction commit or rollback
162  * time. They should not be generated as each field is tweaked.
163  * This for two reasons:
164  * 1) Most editing events make multiple changes to a transaction,
165  * which would generate a flurry of (needless) events, if they
166  * weren't saved up till the commit.
167  * 2) Technically, its incorrect to use transaction data
168  * until the transaction is committed. The GUI element that
169  * is changing the data can look at it, but all of the rest
170  * of the GUI should ignore the data until its committed.
171  */
172 
173 const char *trans_notes_str = "notes";
174 const char *void_reason_str = "void-reason";
175 const char *void_time_str = "void-time";
176 const char *void_former_notes_str = "void-former-notes";
177 const char *trans_is_closing_str = "book_closing";
178 const char *doclink_uri_str = "assoc_uri"; // this is the old name for the document link, kept for compatibility
179 
180 /* KVP entry for date-due value */
181 #define TRANS_DATE_DUE_KVP "trans-date-due"
182 #define TRANS_TXN_TYPE_KVP "trans-txn-type"
183 #define TRANS_READ_ONLY_REASON "trans-read-only"
184 #define TRANS_REVERSED_BY "reversed-by"
185 #define GNC_SX_FROM "from-sched-xaction"
186 
187 #define ISO_DATELENGTH 32 /* length of an iso 8601 date string. */
188 
189 /* This static indicates the debugging module that this .o belongs to. */
190 static QofLogModule log_module = GNC_MOD_ENGINE;
191 
192 enum
193 {
194  PROP_0,
195  PROP_CURRENCY, /* Table */
196  PROP_NUM, /* Table */
197  PROP_POST_DATE, /* Table */
198  PROP_ENTER_DATE, /* Table */
199  PROP_DESCRIPTION, /* Table */
200  PROP_INVOICE, /* KVP */
201  PROP_SX_TXN, /* KVP */
202  PROP_ONLINE_ACCOUNT,/* KVP */
203 };
204 
205 void
206 check_open (const Transaction *trans)
207 {
208  if (trans && 0 >= qof_instance_get_editlevel(trans))
209  PERR ("transaction %p not open for editing", trans);
210 }
211 /********************************************************************\
212 \********************************************************************/
213 gboolean
214 xaccTransStillHasSplit(const Transaction *trans, const Split *s)
215 {
216  return (s && s->parent == trans && !qof_instance_get_destroying(s));
217 }
218 
219 /* Executes 'cmd_block' for each split currently in the transaction,
220  * using the in-edit state. Use the variable 's' for each split. */
221 #define FOR_EACH_SPLIT(trans, cmd_block) if (trans->splits) { \
222  GList *splits; \
223  for (splits = (trans)->splits; splits; splits = splits->next) { \
224  Split *s = splits->data; \
225  if (xaccTransStillHasSplit(trans, s)) { \
226  cmd_block; \
227  } \
228  } \
229  }
230 
231 static inline void mark_trans (Transaction *trans);
232 void mark_trans (Transaction *trans)
233 {
234  FOR_EACH_SPLIT(trans, mark_split(s));
235 }
236 
237 static inline void gen_event_trans (Transaction *trans);
238 void gen_event_trans (Transaction *trans)
239 {
240  GList *node;
241 
242  for (node = trans->splits; node; node = node->next)
243  {
244  Split *s = node->data;
245  Account *account = s->acc;
246  GNCLot *lot = s->lot;
247  if (account)
248  qof_event_gen (&account->inst, GNC_EVENT_ITEM_CHANGED, s);
249 
250  if (lot)
251  {
252  /* A change of transaction date might affect opening date of lot */
253  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, NULL);
254  }
255  }
256 }
257 
258 /* GObject Initialization */
259 G_DEFINE_TYPE(Transaction, gnc_transaction, QOF_TYPE_INSTANCE)
260 
261 static void
262 gnc_transaction_init(Transaction* trans)
263 {
264  ENTER ("trans=%p", trans);
265  /* Fill in some sane defaults */
266  trans->num = CACHE_INSERT("");
267  trans->description = CACHE_INSERT("");
268  trans->common_currency = NULL;
269  trans->splits = NULL;
270  trans->date_entered = 0;
271  trans->date_posted = 0;
272  trans->marker = 0;
273  trans->orig = NULL;
274  trans->txn_type = TXN_TYPE_UNCACHED;
275  LEAVE (" ");
276 }
277 
278 static void
279 gnc_transaction_dispose(GObject *txnp)
280 {
281  G_OBJECT_CLASS(gnc_transaction_parent_class)->dispose(txnp);
282 }
283 
284 static void
285 gnc_transaction_finalize(GObject* txnp)
286 {
287  G_OBJECT_CLASS(gnc_transaction_parent_class)->finalize(txnp);
288 }
289 
290 /* Note that g_value_set_object() refs the object, as does
291  * g_object_get(). But g_object_get() only unrefs once when it disgorges
292  * the object, leaving an unbalanced ref, which leaks. So instead of
293  * using g_value_set_object(), use g_value_take_object() which doesn't
294  * ref the object when used in get_property().
295  */
296 static void
297 gnc_transaction_get_property(GObject* object,
298  guint prop_id,
299  GValue* value,
300  GParamSpec* pspec)
301 {
302  Transaction* tx;
303  Time64 time;
304 
305  g_return_if_fail(GNC_IS_TRANSACTION(object));
306 
307  tx = GNC_TRANSACTION(object);
308  switch (prop_id)
309  {
310  case PROP_NUM:
311  g_value_set_string(value, tx->num);
312  break;
313  case PROP_DESCRIPTION:
314  g_value_set_string(value, tx->description);
315  break;
316  case PROP_CURRENCY:
317  g_value_take_object(value, tx->common_currency);
318  break;
319  case PROP_POST_DATE:
320  time.t = tx->date_posted;
321  g_value_set_boxed(value, &time);
322  break;
323  case PROP_ENTER_DATE:
324  time.t = tx->date_entered;
325  g_value_set_boxed(value, &time);
326  break;
327  case PROP_INVOICE:
328  qof_instance_get_kvp (QOF_INSTANCE (tx), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
329  break;
330  case PROP_SX_TXN:
331  qof_instance_get_kvp (QOF_INSTANCE (tx), value, 1, GNC_SX_FROM);
332  break;
333  case PROP_ONLINE_ACCOUNT:
334  qof_instance_get_kvp (QOF_INSTANCE (tx), value, 1, "online_id");
335  break;
336  default:
337  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
338  break;
339  }
340 }
341 
342 static void
343 gnc_transaction_set_property(GObject* object,
344  guint prop_id,
345  const GValue* value,
346  GParamSpec* pspec)
347 {
348  Transaction* tx;
349  Time64 *t;
350 
351  g_return_if_fail(GNC_IS_TRANSACTION(object));
352 
353  tx = GNC_TRANSACTION(object);
354  g_assert (qof_instance_get_editlevel(tx));
355 
356  switch (prop_id)
357  {
358  case PROP_NUM:
359  xaccTransSetNum( tx, g_value_get_string(value));
360  break;
361  case PROP_DESCRIPTION:
362  xaccTransSetDescription(tx, g_value_get_string(value));
363  break;
364  case PROP_CURRENCY:
365  xaccTransSetCurrency(tx, g_value_get_object(value));
366  break;
367  case PROP_POST_DATE:
368  t = (Time64*)g_value_get_boxed(value);
369  xaccTransSetDatePostedSecs(tx, t->t);
370  break;
371  case PROP_ENTER_DATE:
372  t = (Time64*)g_value_get_boxed(value);
373  xaccTransSetDateEnteredSecs(tx, t->t);
374  break;
375  case PROP_INVOICE:
376  qof_instance_set_kvp (QOF_INSTANCE (tx), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
377  break;
378  case PROP_SX_TXN:
379  qof_instance_set_kvp (QOF_INSTANCE (tx), value, 1, GNC_SX_FROM);
380  break;
381  case PROP_ONLINE_ACCOUNT:
382  qof_instance_set_kvp (QOF_INSTANCE (tx), value, 1, "online_id");
383  break;
384  default:
385  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
386  break;
387  }
388 }
389 
390 static void
391 gnc_transaction_class_init(TransactionClass* klass)
392 {
393  GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
394 
395  gobject_class->dispose = gnc_transaction_dispose;
396  gobject_class->finalize = gnc_transaction_finalize;
397  gobject_class->set_property = gnc_transaction_set_property;
398  gobject_class->get_property = gnc_transaction_get_property;
399 
400  g_object_class_install_property
401  (gobject_class,
402  PROP_NUM,
403  g_param_spec_string("num",
404  "Transaction Number",
405  "The transactionNumber is an arbitrary string "
406  "assigned by the user. It is intended to be "
407  "a short 1-6 character string that is displayed "
408  "by the register. For checks, it is usually the "
409  "check number. For other types of transactions, "
410  "it can be any string.",
411  NULL,
412  G_PARAM_READWRITE));
413 
414  g_object_class_install_property
415  (gobject_class,
416  PROP_DESCRIPTION,
417  g_param_spec_string("description",
418  "Transaction Description",
419  "The transaction description is an arbitrary string "
420  "assigned by the user. It is usually the customer, "
421  "vendor or other organization associated with the "
422  "transaction.",
423  NULL,
424  G_PARAM_READWRITE));
425 
426  g_object_class_install_property
427  (gobject_class,
428  PROP_CURRENCY,
429  g_param_spec_object ("currency",
430  "Currency",
431  "The base currency for this transaction.",
432  GNC_TYPE_COMMODITY,
433  G_PARAM_READWRITE));
434 
435  g_object_class_install_property
436  (gobject_class,
437  PROP_POST_DATE,
438  g_param_spec_boxed("post-date",
439  "Post Date",
440  "The date the transaction occurred.",
441  GNC_TYPE_TIME64,
442  G_PARAM_READWRITE));
443 
444  g_object_class_install_property
445  (gobject_class,
446  PROP_ENTER_DATE,
447  g_param_spec_boxed("enter-date",
448  "Enter Date",
449  "The date the transaction was entered.",
450  GNC_TYPE_TIME64,
451  G_PARAM_READWRITE));
452 
453  g_object_class_install_property(
454  gobject_class,
455  PROP_INVOICE,
456  g_param_spec_boxed("invoice",
457  "Invoice attached to lot",
458  "Used by GncInvoice",
459  GNC_TYPE_GUID,
460  G_PARAM_READWRITE));
461 
462  g_object_class_install_property(
463  gobject_class,
464  PROP_SX_TXN,
465  g_param_spec_boxed("from-sched-xaction",
466  "From Scheduled Transaction",
467  "Used by Scheduled Transastions to record the "
468  "originating template transaction for created "
469  "transactions",
470  GNC_TYPE_GUID,
471  G_PARAM_READWRITE));
472 
473  g_object_class_install_property
474  (gobject_class,
475  PROP_ONLINE_ACCOUNT,
476  g_param_spec_string ("online-id",
477  "Online Account ID",
478  "The online account which corresponds to this "
479  "account for OFX/HCBI import",
480  NULL,
481  G_PARAM_READWRITE));
482 }
483 
484 /********************************************************************\
485  * xaccInitTransaction
486  * Initialize a transaction structure
487 \********************************************************************/
488 
489 static void
490 xaccInitTransaction (Transaction * trans, QofBook *book)
491 {
492  ENTER ("trans=%p", trans);
493  qof_instance_init_data (&trans->inst, GNC_ID_TRANS, book);
494  LEAVE (" ");
495 }
496 
497 /********************************************************************\
498 \********************************************************************/
499 
500 Transaction *
501 xaccMallocTransaction (QofBook *book)
502 {
503  Transaction *trans;
504 
505  g_return_val_if_fail (book, NULL);
506 
507  trans = g_object_new(GNC_TYPE_TRANSACTION, NULL);
508  xaccInitTransaction (trans, book);
509  qof_event_gen (&trans->inst, QOF_EVENT_CREATE, NULL);
510 
511  return trans;
512 }
513 
514 #ifdef DUMP_FUNCTIONS
515 /* Please don't delete this function. Although it is not called by
516  any other code in GnuCash, it is useful when debugging. For example
517  it can be called using the gdb "call" command when stopped at a
518  breakpoint. */
519 void
520 xaccTransDump (const Transaction *trans, const char *tag)
521 {
522  GList *node;
523  char datebuff[MAX_DATE_LENGTH + 1];
524 
525  printf("%s Trans %p", tag, trans);
526  memset(datebuff, 0, sizeof(datebuff));
527  qof_print_date_buff(datebuff, MAX_DATE_LENGTH, trans->date_entered);
528  printf(" Entered: %s\n", datebuff);
529  memset(datebuff, 0, sizeof(datebuff));
530  qof_print_date_buff(datebuff, MAX_DATE_LENGTH, trans->date_posted);
531  printf(" Posted: %s\n", datebuff);
532  printf(" Num: %s\n", trans->num ? trans->num : "(null)");
533  printf(" Description: %s\n",
534  trans->description ? trans->description : "(null)");
535  printf(" Currency: %s\n",
536  gnc_commodity_get_printname(trans->common_currency));
537  printf(" version: %x\n", qof_instance_get_version(trans));
538  printf(" version_chk: %x\n", qof_instance_get_version_check(trans));
539  printf(" editlevel: %x\n", qof_instance_get_editlevel(trans));
540  printf(" orig: %p\n", trans->orig);
541  printf(" idata: %x\n", qof_instance_get_idata(trans));
542  printf(" splits: ");
543  for (node = trans->splits; node; node = node->next)
544  {
545  printf("%p ", node->data);
546  }
547  printf("\n");
548  for (node = trans->splits; node; node = node->next)
549  {
550  xaccSplitDump(node->data, tag);
551  }
552  printf("\n");
553 }
554 #endif
555 
556 void
557 xaccTransSortSplits (Transaction *trans)
558 {
559  GList *node, *new_list = NULL;
560  Split *split;
561 
562  /* first debits */
563  for (node = trans->splits; node; node = node->next)
564  {
565  split = node->data;
567  continue;
568  new_list = g_list_prepend (new_list, split);
569  }
570 
571  /* then credits */
572  for (node = trans->splits; node; node = node->next)
573  {
574  split = node->data;
576  continue;
577  new_list = g_list_prepend (new_list, split);
578  }
579 
580  /* install newly sorted list */
581  g_list_free(trans->splits);
582  trans->splits = g_list_reverse (new_list);
583 }
584 
585 
586 /********************************************************************\
587 \********************************************************************/
588 /* This routine is not exposed externally, since it does weird things,
589  * like not really owning the splits correctly, and other weirdnesses.
590  * This routine is prone to programmer snafu if not used correctly.
591  * It is used only by the edit-rollback code.
592  */
593 static Transaction *
594 dupe_trans (const Transaction *from)
595 {
596  Transaction *to;
597  GList *node;
598 
599  to = g_object_new (GNC_TYPE_TRANSACTION, NULL);
600 
601  CACHE_REPLACE (to->num, from->num);
602  CACHE_REPLACE (to->description, from->description);
603 
604  to->splits = g_list_copy (from->splits);
605  for (node = to->splits; node; node = node->next)
606  {
607  node->data = xaccDupeSplit (node->data);
608  }
609 
610  to->date_entered = from->date_entered;
611  to->date_posted = from->date_posted;
612  qof_instance_copy_version(to, from);
613  to->orig = NULL;
614 
615  to->common_currency = from->common_currency;
616 
617  /* Trash the guid and entity table. We don't want to mistake
618  * the cloned transaction as something official. If we ever
619  * use this transaction, we'll have to fix this up.
620  */
621  to->inst.e_type = NULL;
623  qof_instance_copy_book(to, from);
624  qof_instance_copy_kvp (QOF_INSTANCE(to), QOF_INSTANCE(from));
625 
626  return to;
627 }
628 
629 /********************************************************************\
630  * Use this routine to externally duplicate a transaction. It creates
631  * a full fledged transaction with unique guid, splits, etc. and
632  * writes it to the database.
633 \********************************************************************/
634 Transaction *
635 xaccTransCloneNoKvp (const Transaction *from)
636 {
637  Transaction *to;
638  Split *split;
639  GList *node;
640 
642  to = g_object_new (GNC_TYPE_TRANSACTION, NULL);
643 
644  to->date_entered = from->date_entered;
645  to->date_posted = from->date_posted;
646  CACHE_REPLACE (to->num, from->num);
647  CACHE_REPLACE (to->description, from->description);
648  to->common_currency = from->common_currency;
649  qof_instance_copy_version(to, from);
650  qof_instance_copy_version_check(to, from);
651 
652  to->orig = NULL;
653 
654  qof_instance_init_data (&to->inst, GNC_ID_TRANS,
655  qof_instance_get_book(from));
656 
657  xaccTransBeginEdit(to);
658  for (node = from->splits; node; node = node->next)
659  {
660  split = xaccSplitCloneNoKvp(node->data);
661  split->parent = to;
662  to->splits = g_list_append (to->splits, split);
663  }
664  qof_instance_set_dirty(QOF_INSTANCE(to));
667 
668  return to;
669 }
670 
671 Transaction *
672 xaccTransClone (const Transaction *from)
673 {
674  Transaction *to = xaccTransCloneNoKvp (from);
675 
676  if (g_list_length (to->splits) != g_list_length (from->splits))
677  {
678  PERR ("Cloned transaction has different number of splits from original");
679  xaccTransDestroy (to);
680  return NULL;
681  }
682 
683  xaccTransBeginEdit (to);
684  qof_instance_copy_kvp (QOF_INSTANCE (to), QOF_INSTANCE (from));
685 
686  /* But not the online-id! */
687  qof_instance_set (QOF_INSTANCE (to), "online-id", NULL, NULL);
688 
689  for (GList* lfrom = from->splits, *lto = to->splits; lfrom && lto;
690  lfrom = g_list_next (lfrom), lto = g_list_next (lto))
691  xaccSplitCopyKvp (lfrom->data, lto->data);
692 
693  xaccTransCommitEdit (to);
694  return to;
695 }
696 
697 /*################## Added for Reg2 #################*/
698 
699 /********************************************************************\
700  * Copy a transaction to the 'clipboard' transaction using
701  * dupe_trans. The 'clipboard' transaction must never
702  * be dereferenced.
703 \********************************************************************/
704 Transaction * xaccTransCopyToClipBoard(const Transaction *from_trans)
705 {
706  Transaction *to_trans;
707 
708  if (!from_trans)
709  return NULL;
710 
711  to_trans = dupe_trans(from_trans);
712  return to_trans;
713 }
714 
715 /********************************************************************\
716  * Copy a transaction to another using the function below without
717  * changing any account information.
718 \********************************************************************/
719 void
720 xaccTransCopyOnto(const Transaction *from_trans, Transaction *to_trans)
721 {
722  xaccTransCopyFromClipBoard(from_trans, to_trans, NULL, NULL, TRUE);
723 }
724 
725 /********************************************************************\
726  * This function explicitly must robustly handle some unusual input.
727  *
728  * 'from_trans' may be a duped trans (see dupe_trans), so its
729  * splits may not really belong to the accounts that they say they do.
730  *
731  * 'from_acc' need not be a valid account. It may be an already freed
732  * Account. Therefore, it must not be dereferenced at all.
733  *
734  * Neither 'from_trans', nor 'from_acc', nor any of 'from's splits may
735  * be modified in any way.
736  *
737  * 'no_date' if TRUE will not copy the date posted.
738  *
739  * The 'to_trans' transaction will end up with valid copies of from's
740  * splits. In addition, the copies of any of from's splits that were
741  * in from_acc (or at least claimed to be) will end up in to_acc.
742 \********************************************************************/
743 void
744 xaccTransCopyFromClipBoard(const Transaction *from_trans, Transaction *to_trans,
745  const Account *from_acc, Account *to_acc, gboolean no_date)
746 {
747  gboolean change_accounts = FALSE;
748  GList *node;
749 
750  if (!from_trans || !to_trans)
751  return;
752 
753  change_accounts = from_acc && GNC_IS_ACCOUNT(to_acc) && from_acc != to_acc;
754  xaccTransBeginEdit(to_trans);
755 
756  FOR_EACH_SPLIT(to_trans, xaccSplitDestroy(s));
757  g_list_free(to_trans->splits);
758  to_trans->splits = NULL;
759 
760  xaccTransSetCurrency(to_trans, xaccTransGetCurrency(from_trans));
761  xaccTransSetDescription(to_trans, xaccTransGetDescription(from_trans));
762 
763  if ((xaccTransGetNum(to_trans) == NULL) || (g_strcmp0 (xaccTransGetNum(to_trans), "") == 0))
764  xaccTransSetNum(to_trans, xaccTransGetNum(from_trans));
765 
766  xaccTransSetNotes(to_trans, xaccTransGetNotes(from_trans));
767  xaccTransSetDocLink(to_trans, xaccTransGetDocLink (from_trans));
768  if(!no_date)
769  {
770  xaccTransSetDatePostedSecs(to_trans, xaccTransRetDatePosted (from_trans));
771  }
772 
773  /* Each new split will be parented to 'to' */
774  for (node = from_trans->splits; node; node = node->next)
775  {
776  Split *new_split = xaccMallocSplit( qof_instance_get_book(QOF_INSTANCE(from_trans)));
777  xaccSplitCopyOnto(node->data, new_split);
778  if (change_accounts && xaccSplitGetAccount(node->data) == from_acc)
779  xaccSplitSetAccount(new_split, to_acc);
780  xaccSplitSetParent(new_split, to_trans);
781  }
782  xaccTransCommitEdit(to_trans);
783 }
784 
785 /*################## Added for Reg2 #################*/
786 
787 /********************************************************************\
788  Free the transaction.
789 \********************************************************************/
790 static void
791 xaccFreeTransaction (Transaction *trans)
792 {
793  GList *node;
794 
795  if (!trans) return;
796 
797  ENTER ("(addr=%p)", trans);
798  if (((char *) 1) == trans->num)
799  {
800  PERR ("double-free %p", trans);
801  LEAVE (" ");
802  return;
803  }
804 
805  /* free up the destination splits */
806  for (node = trans->splits; node; node = node->next)
807  xaccFreeSplit (node->data);
808  g_list_free (trans->splits);
809  trans->splits = NULL;
810 
811  /* free up transaction strings */
812  CACHE_REMOVE(trans->num);
813  CACHE_REMOVE(trans->description);
814 
815  /* Just in case someone looks up freed memory ... */
816  trans->num = (char *) 1;
817  trans->description = NULL;
818  trans->date_entered = 0;
819  trans->date_posted = 0;
820  if (trans->orig)
821  {
822  xaccFreeTransaction (trans->orig);
823  trans->orig = NULL;
824  }
825 
826  /* qof_instance_release (&trans->inst); */
827  g_object_unref(trans);
828 
829  LEAVE ("(addr=%p)", trans);
830 }
831 
832 /********************************************************************
833  xaccTransEqual
834 
835  Compare two transactions for equality. We don't pay any attention to
836  rollback issues here, and we only care about equality of "permanent
837  fields", basically the things that would survive a file save/load
838  cycle.
839 
840  ********************************************************************/
841 
842 /* return 0 when splits have equal guids */
843 static gint
844 compare_split_guids (gconstpointer a, gconstpointer b)
845 {
846  const Split *sa = a;
847  const Split *sb = b;
848 
849  if (sa == sb) return 0;
850  if (!sa || !sb) return 1;
851 
852  return guid_compare (xaccSplitGetGUID (sa), xaccSplitGetGUID (sb));
853 }
854 
855 gboolean
856 xaccTransEqual(const Transaction *ta, const Transaction *tb,
857  gboolean check_guids,
858  gboolean check_splits,
859  gboolean check_balances,
860  gboolean assume_ordered)
861 {
862  gboolean same_book;
863 
864  if (!ta && !tb) return TRUE; /* Arguable. FALSE may be better. */
865 
866  if (!ta || !tb)
867  {
868  PINFO ("one is NULL");
869  return FALSE;
870  }
871 
872  if (ta == tb) return TRUE;
873 
874  same_book = qof_instance_get_book(QOF_INSTANCE(ta)) == qof_instance_get_book(QOF_INSTANCE(tb));
875 
876  if (check_guids)
877  {
878  if (qof_instance_guid_compare(ta, tb) != 0)
879  {
880  PINFO ("GUIDs differ");
881  return FALSE;
882  }
883  }
884 
885  if (!gnc_commodity_equal(ta->common_currency, tb->common_currency))
886  {
887  PINFO ("commodities differ %s vs %s",
888  gnc_commodity_get_unique_name (ta->common_currency),
889  gnc_commodity_get_unique_name (tb->common_currency));
890  return FALSE;
891  }
892 
893  if (ta->date_entered != tb->date_entered)
894  {
895  char buf1[100];
896  char buf2[100];
897 
898  (void)gnc_time64_to_iso8601_buff(ta->date_entered, buf1);
899  (void)gnc_time64_to_iso8601_buff(tb->date_entered, buf2);
900  PINFO ("date entered differs: '%s' vs '%s'", buf1, buf2);
901  return FALSE;
902  }
903 
904  if (ta->date_posted != tb->date_posted)
905  {
906  char buf1[100];
907  char buf2[100];
908 
909  (void)gnc_time64_to_iso8601_buff(ta->date_posted, buf1);
910  (void)gnc_time64_to_iso8601_buff(tb->date_posted, buf2);
911  PINFO ("date posted differs: '%s' vs '%s'", buf1, buf2);
912  return FALSE;
913  }
914 
915  /* If the same book, since we use cached strings, we can just compare pointer
916  * equality for num and description
917  */
918  if ((same_book && ta->num != tb->num) || (!same_book && g_strcmp0(ta->num, tb->num) != 0))
919  {
920  PINFO ("num differs: %s vs %s", ta->num, tb->num);
921  return FALSE;
922  }
923 
924  if ((same_book && ta->description != tb->description)
925  || (!same_book && g_strcmp0(ta->description, tb->description)))
926  {
927  PINFO ("descriptions differ: %s vs %s", ta->description, tb->description);
928  return FALSE;
929  }
930 
931  if (qof_instance_compare_kvp (QOF_INSTANCE (ta), QOF_INSTANCE (tb)) != 0)
932  {
933  char *frame_a;
934  char *frame_b;
935 
936  frame_a = qof_instance_kvp_as_string (QOF_INSTANCE (ta));
937  frame_b = qof_instance_kvp_as_string (QOF_INSTANCE (tb));
938 
939 
940  PINFO ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
941 
942  g_free (frame_a);
943  g_free (frame_b);
944 
945  return FALSE;
946  }
947 
948  if (check_splits)
949  {
950  if ((!ta->splits && tb->splits) || (!tb->splits && ta->splits))
951  {
952  PINFO ("only one has splits");
953  return FALSE;
954  }
955 
956  if (ta->splits && tb->splits)
957  {
958  GList *node_a, *node_b;
959 
960  for (node_a = ta->splits, node_b = tb->splits;
961  node_a;
962  node_a = node_a->next, node_b = node_b->next)
963  {
964  Split *split_a = node_a->data;
965  Split *split_b;
966 
967  /* don't presume that the splits are in the same order */
968  if (!assume_ordered)
969  node_b = g_list_find_custom (tb->splits, split_a,
970  compare_split_guids);
971 
972  if (!node_b)
973  {
974  gchar guidstr[GUID_ENCODING_LENGTH+1];
975  guid_to_string_buff (xaccSplitGetGUID (split_a),guidstr);
976 
977  PINFO ("first has split %s and second does not",guidstr);
978  return FALSE;
979  }
980 
981  split_b = node_b->data;
982 
983  if (!xaccSplitEqual (split_a, split_b, check_guids, check_balances,
984  FALSE))
985  {
986  char str_a[GUID_ENCODING_LENGTH + 1];
987  char str_b[GUID_ENCODING_LENGTH + 1];
988 
989  guid_to_string_buff (xaccSplitGetGUID (split_a), str_a);
990  guid_to_string_buff (xaccSplitGetGUID (split_b), str_b);
991 
992  PINFO ("splits %s and %s differ", str_a, str_b);
993  return FALSE;
994  }
995  }
996 
997  if (g_list_length (ta->splits) != g_list_length (tb->splits))
998  {
999  PINFO ("different number of splits");
1000  return FALSE;
1001  }
1002  }
1003  }
1004 
1005  return TRUE;
1006 }
1007 
1008 /********************************************************************\
1009 xaccTransUseTradingAccounts
1010 
1011 Returns true if the transaction should include trading account splits if
1012 it involves more than one commodity.
1013 \********************************************************************/
1014 
1015 gboolean xaccTransUseTradingAccounts(const Transaction *trans)
1016 {
1018 }
1019 
1020 /********************************************************************\
1021 \********************************************************************/
1022 
1023 Transaction *
1024 xaccTransLookup (const GncGUID *guid, QofBook *book)
1025 {
1026  QofCollection *col;
1027  if (!guid || !book) return NULL;
1028  col = qof_book_get_collection (book, GNC_ID_TRANS);
1029  return (Transaction *) qof_collection_lookup_entity (col, guid);
1030 }
1031 
1032 /********************************************************************\
1033 \********************************************************************/
1034 
1035 gnc_numeric
1036 xaccTransGetImbalanceValue (const Transaction * trans)
1037 {
1038  gnc_numeric imbal = gnc_numeric_zero();
1039  if (!trans) return imbal;
1040 
1041  ENTER("(trans=%p)", trans);
1042  /* Could use xaccSplitsComputeValue, except that we want to use
1043  GNC_HOW_DENOM_EXACT */
1044  FOR_EACH_SPLIT(trans, imbal =
1047  LEAVE("(trans=%p) imbal=%s", trans, gnc_num_dbg_to_string(imbal));
1048  return imbal;
1049 }
1050 
1051 MonetaryList *
1052 xaccTransGetImbalance (const Transaction * trans)
1053 {
1054  /* imbal_value is used if either (1) the transaction has a non currency
1055  split or (2) all the splits are in the same currency. If there are
1056  no non-currency splits and not all splits are in the same currency then
1057  imbal_list is used to compute the imbalance. */
1058  MonetaryList *imbal_list = NULL;
1059  gnc_numeric imbal_value = gnc_numeric_zero();
1060  gboolean trading_accts;
1061 
1062  if (!trans) return imbal_list;
1063 
1064  ENTER("(trans=%p)", trans);
1065 
1066  trading_accts = xaccTransUseTradingAccounts (trans);
1067 
1068  /* If using trading accounts and there is at least one split that is not
1069  in the transaction currency or a split that has a price or exchange
1070  rate other than 1, then compute the balance in each commodity in the
1071  transaction. Otherwise (all splits are in the transaction's currency)
1072  then compute the balance using the value fields.
1073 
1074  Optimize for the common case of only one currency and a balanced
1075  transaction. */
1076  FOR_EACH_SPLIT(trans,
1077  {
1078  gnc_commodity *commodity;
1080  if (trading_accts &&
1081  (imbal_list ||
1082  ! gnc_commodity_equiv(commodity, trans->common_currency) ||
1084  {
1085  /* Need to use (or already are using) a list of imbalances in each of
1086  the currencies used in the transaction. */
1087  if (! imbal_list)
1088  {
1089  /* All previous splits have been in the transaction's common
1090  currency, so imbal_value is in this currency. */
1091  imbal_list = gnc_monetary_list_add_value(imbal_list,
1092  trans->common_currency,
1093  imbal_value);
1094  }
1095  imbal_list = gnc_monetary_list_add_value(imbal_list, commodity,
1096  xaccSplitGetAmount(s));
1097  }
1098 
1099  /* Add it to the value accumulator in case we need it. */
1100  imbal_value = gnc_numeric_add(imbal_value, xaccSplitGetValue(s),
1102  } );
1103 
1104 
1105  if (!imbal_list && !gnc_numeric_zero_p(imbal_value))
1106  {
1107  /* Not balanced and no list, create one. If we found multiple currencies
1108  and no non-currency commodity then imbal_list will already exist and
1109  we won't get here. */
1110  imbal_list = gnc_monetary_list_add_value(imbal_list,
1111  trans->common_currency,
1112  imbal_value);
1113  }
1114 
1115  /* Delete all the zero entries from the list, perhaps leaving an
1116  empty list */
1117  imbal_list = gnc_monetary_list_delete_zeros(imbal_list);
1118 
1119  LEAVE("(trans=%p), imbal=%p", trans, imbal_list);
1120  return imbal_list;
1121 }
1122 
1123 gboolean
1124 xaccTransIsBalanced (const Transaction *trans)
1125 {
1126  MonetaryList *imbal_list;
1127  gboolean result;
1128  gnc_numeric imbal = gnc_numeric_zero();
1129  gnc_numeric imbal_trading = gnc_numeric_zero();
1130 
1131  if (trans == NULL) return FALSE;
1132 
1133  if (xaccTransUseTradingAccounts(trans))
1134  {
1135  /* Transaction is imbalanced if the value is imbalanced in either
1136  trading or non-trading splits. One can't be used to balance
1137  the other. */
1138  FOR_EACH_SPLIT(trans,
1139  {
1140  Account *acc = xaccSplitGetAccount(s);
1141  if (!acc || xaccAccountGetType(acc) != ACCT_TYPE_TRADING)
1142  {
1143  imbal = gnc_numeric_add(imbal, xaccSplitGetValue(s),
1145  }
1146  else
1147  {
1148  imbal_trading = gnc_numeric_add(imbal_trading, xaccSplitGetValue(s),
1150  }
1151  }
1152  );
1153  }
1154  else
1155  imbal = xaccTransGetImbalanceValue(trans);
1156 
1157  if (! gnc_numeric_zero_p(imbal) || ! gnc_numeric_zero_p(imbal_trading))
1158  return FALSE;
1159 
1160  if (!xaccTransUseTradingAccounts (trans))
1161  return TRUE;
1162 
1163  imbal_list = xaccTransGetImbalance(trans);
1164  result = imbal_list == NULL;
1165  gnc_monetary_list_free(imbal_list);
1166  return result;
1167 }
1168 
1169 gnc_numeric
1170 xaccTransGetAccountValue (const Transaction *trans,
1171  const Account *acc)
1172 {
1173  gnc_numeric total = gnc_numeric_zero ();
1174  if (!trans || !acc) return total;
1175 
1176  FOR_EACH_SPLIT(trans, if (acc == xaccSplitGetAccount(s))
1177 {
1178  total = gnc_numeric_add (total, xaccSplitGetValue (s),
1181  });
1182  return total;
1183 }
1184 
1185 gnc_numeric
1186 xaccTransGetAccountAmount (const Transaction *trans, const Account *acc)
1187 {
1188  gnc_numeric total = gnc_numeric_zero ();
1189  if (!trans || !acc) return total;
1190 
1191  total = gnc_numeric_convert (total, xaccAccountGetCommoditySCU (acc),
1193  FOR_EACH_SPLIT(trans, if (acc == xaccSplitGetAccount(s))
1194  total = gnc_numeric_add_fixed(
1195  total, xaccSplitGetAmount(s)));
1196  return total;
1197 }
1198 
1199 /*################## Added for Reg2 #################*/
1200 gboolean
1201 xaccTransGetRateForCommodity(const Transaction *trans,
1202  const gnc_commodity *split_com,
1203  const Split *split, gnc_numeric *rate)
1204 {
1205  GList *splits;
1206  gnc_commodity *trans_curr;
1207 
1208  if (trans == NULL || split_com == NULL || split == NULL)
1209  return FALSE;
1210 
1211  trans_curr = xaccTransGetCurrency (trans);
1212  if (gnc_commodity_equal (trans_curr, split_com))
1213  {
1214  if (rate)
1215  *rate = gnc_numeric_create (1, 1);
1216  return TRUE;
1217  }
1218 
1219  for (splits = trans->splits; splits; splits = splits->next)
1220  {
1221  Split *s = splits->data;
1222  gnc_commodity *comm;
1223 
1224  if (!xaccTransStillHasSplit (trans, s)) continue;
1225 
1226  if (s == split)
1227  {
1229  if (gnc_commodity_equal (split_com, comm))
1230  {
1231  gnc_numeric amt = xaccSplitGetAmount (s);
1232  gnc_numeric val = xaccSplitGetValue (s);
1233 
1236  {
1237  if (rate)
1238  *rate = gnc_numeric_div (amt, val, GNC_DENOM_AUTO,
1240  return TRUE;
1241  }
1242  }
1243  }
1244  }
1245  return FALSE;
1246 }
1247 /*################## Added for Reg2 #################*/
1248 
1249 gnc_numeric
1250 xaccTransGetAccountConvRate(const Transaction *txn, const Account *acc)
1251 {
1252  gnc_numeric amount, value, convrate;
1253  GList *splits;
1254  Split *s;
1255  gboolean found_acc_match = FALSE;
1256  gnc_commodity *acc_commod = xaccAccountGetCommodity(acc);
1257 
1258  /* We need to compute the conversion rate into _this account_. So,
1259  * find the first split into this account, compute the conversion
1260  * rate (based on amount/value), and then return this conversion
1261  * rate.
1262  */
1263  if (gnc_commodity_equal(acc_commod, xaccTransGetCurrency(txn)))
1264  return gnc_numeric_create(1, 1);
1265 
1266  for (splits = txn->splits; splits; splits = splits->next)
1267  {
1268  Account *split_acc;
1269  gnc_commodity *split_commod;
1270 
1271  s = splits->data;
1272 
1273  if (!xaccTransStillHasSplit(txn, s))
1274  continue;
1275  split_acc = xaccSplitGetAccount (s);
1276  split_commod = xaccAccountGetCommodity (split_acc);
1277  if (! (split_acc == acc ||
1278  gnc_commodity_equal (split_commod, acc_commod)))
1279  continue;
1280 
1281  found_acc_match = TRUE;
1282  amount = xaccSplitGetAmount (s);
1283 
1284  /* Ignore splits with "zero" amount */
1285  if (gnc_numeric_zero_p (amount))
1286  continue;
1287 
1288  value = xaccSplitGetValue (s);
1289  if (gnc_numeric_zero_p (value))
1290  PWARN("How can amount be nonzero and value be zero?");
1291 
1292  convrate = gnc_numeric_div(amount, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
1293  return convrate;
1294  }
1295 
1296  if (acc)
1297  {
1298  /* If we did find a matching account but its amount was zero,
1299  * then perhaps this is a "special" income/loss transaction
1300  */
1301  if (found_acc_match)
1302  return gnc_numeric_zero();
1303  else
1304  PERR("Cannot convert transaction -- no splits with proper conversion ratio");
1305  }
1306  return gnc_numeric_create (100, 100);
1307 }
1308 
1309 gnc_numeric
1310 xaccTransGetAccountBalance (const Transaction *trans,
1311  const Account *account)
1312 {
1313  GList *node;
1314  Split *last_split = NULL;
1315 
1316  // Not really the appropriate error value.
1317  g_return_val_if_fail(account && trans, gnc_numeric_error(GNC_ERROR_ARG));
1318 
1319  for (node = trans->splits; node; node = node->next)
1320  {
1321  Split *split = node->data;
1322 
1323  if (!xaccTransStillHasSplit(trans, split))
1324  continue;
1325  if (xaccSplitGetAccount(split) != account)
1326  continue;
1327 
1328  if (!last_split)
1329  {
1330  last_split = split;
1331  continue;
1332  }
1333 
1334  /* This test needs to correspond to the comparison function used when
1335  sorting the splits for computing the running balance. */
1336  if (xaccSplitOrder (last_split, split) < 0)
1337  last_split = split;
1338  }
1339 
1340  return xaccSplitGetBalance (last_split);
1341 }
1342 
1343 /********************************************************************\
1344 \********************************************************************/
1345 /* The new routine for setting the common currency */
1346 
1347 gnc_commodity *
1348 xaccTransGetCurrency (const Transaction *trans)
1349 {
1350  return trans ? trans->common_currency : NULL;
1351 }
1352 
1353 /* Helper functions for xaccTransSetCurrency */
1354 static gnc_numeric
1355 find_new_rate(Transaction *trans, gnc_commodity *curr)
1356 {
1357  GList *node;
1358  gnc_numeric rate = gnc_numeric_zero();
1359  for (node = trans->splits; node != NULL; node = g_list_next (node))
1360  {
1361  Split *split = GNC_SPLIT(node->data);
1362  gnc_commodity *split_com =
1364  if (gnc_commodity_equal(curr, split_com))
1365  {
1366 /* This looks backwards, but the amount of the balancing transaction
1367  * that we're going to use it on is in the value's currency. */
1368  rate = gnc_numeric_div(xaccSplitGetAmount(split),
1369  xaccSplitGetValue(split),
1371  break;
1372  }
1373  }
1374  return rate;
1375 }
1376 
1377 static void
1378 split_set_new_value(Split* split, gnc_commodity *curr, gnc_commodity *old_curr,
1379  gnc_numeric rate)
1380 {
1381  gnc_commodity *split_com =
1383  if (gnc_commodity_equal(curr, split_com))
1384  xaccSplitSetValue(split, xaccSplitGetAmount(split));
1385  else if (gnc_commodity_equal(old_curr, split_com))
1386  xaccSplitSetSharePrice(split, rate);
1387  else
1388  {
1389  gnc_numeric old_rate = gnc_numeric_div(xaccSplitGetValue(split),
1390  xaccSplitGetAmount(split),
1393  gnc_numeric new_rate = gnc_numeric_div(old_rate, rate, GNC_DENOM_AUTO,
1395  xaccSplitSetSharePrice(split, new_rate);
1396  }
1397 }
1398 
1406 void
1407 xaccTransSetCurrency (Transaction *trans, gnc_commodity *curr)
1408 {
1409  gnc_commodity *old_curr = trans->common_currency;
1410  if (!trans || !curr || trans->common_currency == curr) return;
1411  xaccTransBeginEdit(trans);
1412 
1413  trans->common_currency = curr;
1414  if (old_curr != NULL && trans->splits != NULL)
1415  {
1416  gnc_numeric rate = find_new_rate(trans, curr);
1417  if (!gnc_numeric_zero_p (rate))
1418  {
1419  FOR_EACH_SPLIT(trans, split_set_new_value(s, curr, old_curr, rate));
1420  }
1421  else
1422  {
1423  FOR_EACH_SPLIT(trans, xaccSplitSetValue(s, xaccSplitGetValue(s)));
1424  }
1425  }
1426 
1427  qof_instance_set_dirty(QOF_INSTANCE(trans));
1428  mark_trans(trans); /* Dirty balance of every account in trans */
1429  xaccTransCommitEdit(trans);
1430 }
1431 
1432 /********************************************************************\
1433 \********************************************************************/
1434 
1435 void
1436 xaccTransBeginEdit (Transaction *trans)
1437 {
1438  if (!trans) return;
1439  if (!qof_begin_edit(&trans->inst)) return;
1440 
1441  if (qof_book_shutting_down(qof_instance_get_book(trans))) return;
1442 
1444  {
1445  xaccOpenLog ();
1446  xaccTransWriteLog (trans, 'B');
1447  }
1448 
1449  /* Make a clone of the transaction; we will use this
1450  * in case we need to roll-back the edit. */
1451  trans->orig = dupe_trans (trans);
1452 }
1453 
1454 /********************************************************************\
1455 \********************************************************************/
1456 
1457 void
1458 xaccTransDestroy (Transaction *trans)
1459 {
1460  if (!trans) return;
1461 
1462  if (!xaccTransGetReadOnly (trans) ||
1464  {
1465  xaccTransBeginEdit(trans);
1466  qof_instance_set_destroying(trans, TRUE);
1467  xaccTransCommitEdit(trans);
1468  }
1469 }
1470 
1471 static void
1472 destroy_gains (Transaction *trans)
1473 {
1474  SplitList *node;
1475  for (node = trans->splits; node; node = node->next)
1476  {
1477  Split *s = node->data;
1478  if (!xaccTransStillHasSplit(trans, s))
1479  continue;
1480 
1481  if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus(s);
1482  if (s->gains_split && (GAINS_STATUS_GAINS & s->gains_split->gains))
1483  {
1484  Transaction *t = s->gains_split->parent;
1485  xaccTransDestroy (t);
1486  s->gains_split = NULL;
1487  }
1488  }
1489 }
1490 
1491 static void
1492 do_destroy (Transaction *trans)
1493 {
1494  SplitList *node;
1495  gboolean shutting_down = qof_book_shutting_down(qof_instance_get_book(trans));
1496 
1497  /* If there are capital-gains transactions associated with this,
1498  * they need to be destroyed too unless we're shutting down in
1499  * which case all transactions will be destroyed. */
1500  if (!shutting_down)
1501  destroy_gains (trans);
1502 
1503  /* Make a log in the journal before destruction. */
1504  if (!shutting_down && !qof_book_is_readonly(qof_instance_get_book(trans)))
1505  xaccTransWriteLog (trans, 'D');
1506 
1507  qof_event_gen (&trans->inst, QOF_EVENT_DESTROY, NULL);
1508 
1509  /* We only own the splits that still think they belong to us. This is done
1510  in 2 steps. In the first, the splits are marked as being destroyed, but they
1511  are not destroyed yet. In the second, the destruction is committed which will
1512  do the actual destruction. If both steps are done for a split before they are
1513  done for the next split, then a split will still be on the split list after it
1514  has been freed. This can cause other parts of the code (e.g. in xaccSplitDestroy())
1515  to reference the split after it has been freed. */
1516  for (node = trans->splits; node; node = node->next)
1517  {
1518  Split *s = node->data;
1519  if (s && s->parent == trans)
1520  {
1521  xaccSplitDestroy(s);
1522  }
1523  }
1524  for (node = trans->splits; node; node = node->next)
1525  {
1526  Split *s = node->data;
1527  if (s && s->parent == trans)
1528  {
1529  xaccSplitCommitEdit(s);
1530  }
1531  }
1532  g_list_free (trans->splits);
1533  trans->splits = NULL;
1534  xaccFreeTransaction (trans);
1535 }
1536 
1537 /********************************************************************\
1538 \********************************************************************/
1539 
1540 /* Temporary hack for data consistency */
1541 static int scrub_data = 1;
1542 void xaccEnableDataScrubbing(void)
1543 {
1544  scrub_data = 1;
1545 }
1546 void xaccDisableDataScrubbing(void)
1547 {
1548  scrub_data = 0;
1549 }
1550 
1551 /* Check for an implicitly deleted transaction */
1552 static gboolean was_trans_emptied(Transaction *trans)
1553 {
1554  FOR_EACH_SPLIT(trans, return FALSE);
1555  return TRUE;
1556 }
1557 
1558 static void trans_on_error(Transaction *trans, QofBackendError errcode)
1559 {
1560  /* If the backend puked, then we must roll-back
1561  * at this point, and let the user know that we failed.
1562  * The GUI should check for error conditions ...
1563  */
1564  if (ERR_BACKEND_MODIFIED == errcode)
1565  {
1566  PWARN("Another user has modified this transaction\n"
1567  "\tjust a moment ago. Please look at their changes,\n"
1568  "\tand try again, if needed.\n");
1569  }
1570 
1571  xaccTransRollbackEdit(trans);
1572  gnc_engine_signal_commit_error( errcode );
1573 }
1574 
1575 static void trans_cleanup_commit(Transaction *trans)
1576 {
1577  GList *slist, *node;
1578 
1579  /* ------------------------------------------------- */
1580  /* Make sure all associated splits are in proper order
1581  * in their accounts with the correct balances. */
1582 
1583  /* Iterate over existing splits */
1584  slist = g_list_copy(trans->splits);
1585  for (node = slist; node; node = node->next)
1586  {
1587  Split *s = node->data;
1588  if (!qof_instance_is_dirty(QOF_INSTANCE(s)))
1589  continue;
1590 
1591  if ((s->parent != trans) || qof_instance_get_destroying(s))
1592  {
1593  /* Existing split either moved to another transaction or
1594  was destroyed, drop from list */
1595  GncEventData ed;
1596  ed.node = trans;
1597  ed.idx = g_list_index(trans->splits, s);
1598  trans->splits = g_list_remove(trans->splits, s);
1599  qof_event_gen(&s->inst, QOF_EVENT_REMOVE, &ed);
1600  }
1601 
1602  if (s->parent == trans)
1603  {
1604  /* Split was either added, destroyed or just changed */
1606  qof_event_gen(&s->inst, QOF_EVENT_DESTROY, NULL);
1607  else qof_event_gen(&s->inst, QOF_EVENT_MODIFY, NULL);
1608  xaccSplitCommitEdit(s);
1609  }
1610  }
1611  g_list_free(slist);
1612 
1614  xaccTransWriteLog (trans, 'C');
1615 
1616  /* Get rid of the copy we made. We won't be rolling back,
1617  * so we don't need it any more. */
1618  PINFO ("get rid of rollback trans=%p", trans->orig);
1619  xaccFreeTransaction (trans->orig);
1620  trans->orig = NULL;
1621 
1622  /* Sort the splits. Why do we need to do this ?? */
1623  /* Good question. Who knows? */
1624  xaccTransSortSplits(trans);
1625 
1626  /* Put back to zero. */
1627  qof_instance_decrease_editlevel(trans);
1628  g_assert(qof_instance_get_editlevel(trans) == 0);
1629 
1630  gen_event_trans (trans); //TODO: could be conditional
1631  qof_event_gen (&trans->inst, QOF_EVENT_MODIFY, NULL);
1632 }
1633 
1634 void
1635 xaccTransCommitEdit (Transaction *trans)
1636 {
1637  if (!trans) return;
1638  ENTER ("(trans=%p)", trans);
1639 
1640  if (!qof_commit_edit (QOF_INSTANCE(trans)))
1641  {
1642  LEAVE("editlevel non-zero");
1643  return;
1644  }
1645 
1646  /* We increment this for the duration of the call
1647  * so other functions don't result in a recursive
1648  * call to xaccTransCommitEdit. */
1649  qof_instance_increase_editlevel(trans);
1650 
1651  if (was_trans_emptied(trans))
1652  qof_instance_set_destroying(trans, TRUE);
1653 
1654  /* Before committing the transaction, we are going to enforce certain
1655  * constraints. In particular, we want to enforce the cap-gains
1656  * and the balanced lot constraints. These constraints might
1657  * change the number of splits in this transaction, and the
1658  * transaction itself might be deleted. This is also why
1659  * we can't really enforce these constraints elsewhere: they
1660  * can cause pointers to splits and transactions to disappear out
1661  * from under the holder.
1662  */
1663  if (!qof_instance_get_destroying(trans) && scrub_data &&
1665  {
1666  /* If scrubbing gains recurses through here, don't call it again. */
1667  scrub_data = 0;
1668  /* The total value of the transaction should sum to zero.
1669  * Call the trans scrub routine to fix it. Indirectly, this
1670  * routine also performs a number of other transaction fixes too.
1671  */
1672  xaccTransScrubImbalance (trans, NULL, NULL);
1673  /* Get the cap gains into a consistent state as well. */
1674 
1675  /* Lot Scrubbing is temporarily disabled. */
1676  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
1677  xaccTransScrubGains (trans, NULL);
1678 
1679  /* Allow scrubbing in transaction commit again */
1680  scrub_data = 1;
1681  }
1682 
1683  /* Record the time of last modification */
1684  if (0 == trans->date_entered)
1685  {
1686  trans->date_entered = gnc_time(NULL);
1687  qof_instance_set_dirty(QOF_INSTANCE(trans));
1688  }
1689 
1690  trans->txn_type = TXN_TYPE_UNCACHED;
1691  qof_commit_edit_part2(QOF_INSTANCE(trans),
1692  (void (*) (QofInstance *, QofBackendError))
1693  trans_on_error,
1694  (void (*) (QofInstance *)) trans_cleanup_commit,
1695  (void (*) (QofInstance *)) do_destroy);
1696  LEAVE ("(trans=%p)", trans);
1697 }
1698 
1699 #define SWAP_STR(a, b) do { const char *tmp = (a); (a) = (b); (b) = tmp; } while (0);
1700 #define SWAP(a, b) do { gpointer tmp = (a); (a) = (b); (b) = tmp; } while (0);
1701 
1702 /* Ughhh. The Rollback function is terribly complex, and, what's worse,
1703  * it only rolls back the basics. The TransCommit functions did a bunch
1704  * of Lot/Cap-gains scrubbing that don't get addressed/undone here, and
1705  * so the rollback can potentially leave a bit of a mess behind. We
1706  * really need a more robust undo capability. Part of the problem is
1707  * that the biggest user of the undo is the multi-user backend, which
1708  * also adds complexity.
1709  */
1710 void
1711 xaccTransRollbackEdit (Transaction *trans)
1712 {
1713  GList *node, *onode;
1714  QofBackend *be;
1715  Transaction *orig;
1716  GList *slist;
1717  int num_preexist, i;
1718 
1719 /* FIXME: This isn't quite the right way to handle nested edits --
1720  * there should be a stack of transaction states that are popped off
1721  * and restored at each level -- but it does prevent restoring to the
1722  * editlevel 0 state until one is returning to editlevel 0, and
1723  * thereby prevents a crash caused by trans->orig getting NULLed too
1724  * soon.
1725  */
1726  if (!qof_instance_get_editlevel (QOF_INSTANCE (trans))) return;
1727  if (qof_instance_get_editlevel (QOF_INSTANCE (trans)) > 1) {
1728  qof_instance_decrease_editlevel (QOF_INSTANCE (trans));
1729  return;
1730  }
1731 
1732  ENTER ("trans addr=%p\n", trans);
1733 
1734  check_open(trans);
1735 
1736  /* copy the original values back in. */
1737 
1738  orig = trans->orig;
1739  SWAP_STR(trans->num, orig->num);
1740  SWAP_STR(trans->description, orig->description);
1741  trans->date_entered = orig->date_entered;
1742  trans->date_posted = orig->date_posted;
1743  SWAP(trans->common_currency, orig->common_currency);
1744  qof_instance_swap_kvp (QOF_INSTANCE (trans), QOF_INSTANCE (orig));
1745 
1746  /* The splits at the front of trans->splits are exactly the same
1747  splits as in the original, but some of them may have changed, so
1748  we restore only those. */
1749 /* FIXME: Runs off the transaction's splits, so deleted splits are not
1750  * restored!
1751  */
1752  num_preexist = g_list_length(orig->splits);
1753  slist = g_list_copy(trans->splits);
1754  for (i = 0, node = slist, onode = orig->splits; node;
1755  i++, node = node->next, onode = onode ? onode->next : NULL)
1756  {
1757  Split *s = node->data;
1758 
1759  if (!qof_instance_is_dirty(QOF_INSTANCE(s)))
1760  continue;
1761 
1762  if (i < num_preexist && onode)
1763  {
1764  Split *so = onode->data;
1765 
1766  xaccSplitRollbackEdit(s);
1767  SWAP_STR(s->action, so->action);
1768  SWAP_STR(s->memo, so->memo);
1769  qof_instance_copy_kvp (QOF_INSTANCE (s), QOF_INSTANCE (so));
1770  s->reconciled = so->reconciled;
1771  s->amount = so->amount;
1772  s->value = so->value;
1773  s->lot = so->lot;
1774  s->gains_split = so->gains_split;
1775  //SET_GAINS_A_VDIRTY(s);
1776  s->date_reconciled = so->date_reconciled;
1777  qof_instance_mark_clean(QOF_INSTANCE(s));
1778  }
1779  else
1780  {
1781  /* Potentially added splits */
1782  if (trans != xaccSplitGetParent(s))
1783  {
1784  trans->splits = g_list_remove(trans->splits, s);
1785  /* New split added, but then moved to another
1786  transaction */
1787  continue;
1788  }
1789  xaccSplitRollbackEdit(s);
1790  trans->splits = g_list_remove(trans->splits, s);
1791  g_assert(trans != xaccSplitGetParent(s));
1792  /* NB: our memory management policy here is that a new split
1793  added to the transaction which is then rolled-back still
1794  belongs to the engine. Specifically, it's freed by the
1795  transaction to which it was added. Don't add the Split to
1796  more than one transaction during the begin/commit block! */
1797  if (NULL == xaccSplitGetParent(s))
1798  {
1799  xaccFreeSplit(s); // a newly malloc'd split
1800  }
1801  }
1802  }
1803  g_list_free(slist);
1804 
1805  // orig->splits may still have duped splits so free them
1806  for (node = orig->splits; node; node = node->next)
1807  xaccFreeSplit(node->data);
1808  g_list_free(orig->splits);
1809  orig->splits = NULL;
1810 
1811  /* Now that the engine copy is back to its original version,
1812  * get the backend to fix it in the database */
1816  if (qof_backend_can_rollback (be))
1817  {
1818  QofBackendError errcode;
1819 
1820  /* clear errors */
1821  do
1822  {
1823  errcode = qof_backend_get_error (be);
1824  }
1825  while (ERR_BACKEND_NO_ERR != errcode);
1826 
1827  qof_backend_rollback_instance (be, &(trans->inst));
1828 
1829  errcode = qof_backend_get_error (be);
1830  if (ERR_BACKEND_MOD_DESTROY == errcode)
1831  {
1832  /* The backend is asking us to delete this transaction.
1833  * This typically happens because another (remote) user
1834  * has deleted this transaction, and we haven't found
1835  * out about it until this user tried to edit it.
1836  */
1837  xaccTransDestroy (trans);
1838  do_destroy (trans);
1839 
1840  /* push error back onto the stack */
1841  qof_backend_set_error (be, errcode);
1842  LEAVE ("deleted trans addr=%p\n", trans);
1843  return;
1844  }
1845  if (ERR_BACKEND_NO_ERR != errcode)
1846  {
1847  PERR ("Rollback Failed. Ouch!");
1848  /* push error back onto the stack */
1849  qof_backend_set_error (be, errcode);
1850  }
1851  }
1852 
1854  xaccTransWriteLog (trans, 'R');
1855 
1856  xaccFreeTransaction (trans->orig);
1857 
1858  trans->orig = NULL;
1859  qof_instance_set_destroying(trans, FALSE);
1860 
1861  /* Put back to zero. */
1862  qof_instance_decrease_editlevel(trans);
1863  /* FIXME: The register code seems to depend on the engine to
1864  generate an event during rollback, even though the state is just
1865  reverting to what it was. */
1866  gen_event_trans (trans);
1867 
1868  LEAVE ("trans addr=%p\n", trans);
1869 }
1870 
1871 gboolean
1872 xaccTransIsOpen (const Transaction *trans)
1873 {
1874  return trans ? (0 < qof_instance_get_editlevel(trans)) : FALSE;
1875 }
1876 
1877 #define SECS_PER_DAY 86400
1878 
1879 int
1880 xaccTransOrder (const Transaction *ta, const Transaction *tb)
1881 {
1882  return xaccTransOrder_num_action (ta, NULL, tb, NULL);
1883 }
1884 
1885 /* Order a pair of potentially numeric string as numbers if both
1886  * strings begin with numbers, ordering the remainder of the string
1887  * lexically if the numeric parts are equal, and the whole strings
1888  * lexically otherwise.
1889  *
1890  * Note that this won't work well for numbers > 10^18 and that
1891  * negative numbers are treated as strings and will cause the pair to
1892  * be ordered lexically.
1893  */
1894 
1895 static int
1896 order_by_int64_or_string (const char* a, const char* b)
1897 {
1898  char *end_a = NULL, *end_b = NULL;
1899  int cmp = 0;
1900  uint64_t na = strtoull(a, &end_a, 10);
1901  uint64_t nb = strtoull(b, &end_b, 10);
1902  if (na && nb)
1903  {
1904  if (na != nb)
1905  return na < nb ? -1 : 1;
1906  cmp = g_utf8_collate(end_a, end_b);
1907  }
1908  else
1909  {
1910  cmp = g_utf8_collate(a, b);
1911  }
1912  return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
1913 }
1914 
1915 int
1916 xaccTransOrder_num_action (const Transaction *ta, const char *actna,
1917  const Transaction *tb, const char *actnb)
1918 {
1919  const char *da, *db;
1920  int retval;
1921 
1922  if ( ta && !tb ) return -1;
1923  if ( !ta && tb ) return +1;
1924  if ( !ta && !tb ) return 0;
1925 
1926  if (ta->date_posted != tb->date_posted)
1927  return (ta->date_posted > tb->date_posted) - (ta->date_posted < tb->date_posted);
1928 
1929  /* Always sort closing transactions after normal transactions */
1930  {
1931  gboolean ta_is_closing = xaccTransGetIsClosingTxn (ta);
1932  gboolean tb_is_closing = xaccTransGetIsClosingTxn (tb);
1933  if (ta_is_closing != tb_is_closing)
1934  return (ta_is_closing - tb_is_closing);
1935  }
1936 
1937  /* otherwise, sort on number string */
1938  if (actna && actnb) /* split action string, if not NULL */
1939  {
1940  retval = order_by_int64_or_string (actna, actnb);
1941  }
1942  else /* else transaction num string */
1943  {
1944  retval = order_by_int64_or_string (ta->num, tb->num);
1945  }
1946  if (retval)
1947  return retval;
1948 
1949  if (ta->date_entered != tb->date_entered)
1950  return (ta->date_entered > tb->date_entered) - (ta->date_entered < tb->date_entered);
1951 
1952  /* otherwise, sort on description string */
1953  da = ta->description ? ta->description : "";
1954  db = tb->description ? tb->description : "";
1955  retval = g_utf8_collate (da, db);
1956  if (retval)
1957  return retval;
1958 
1959  /* else, sort on guid - keeps sort stable. */
1960  return qof_instance_guid_compare(ta, tb);
1961 }
1962 
1963 /********************************************************************\
1964 \********************************************************************/
1965 
1966 static inline void
1967 xaccTransSetDateInternal(Transaction *trans, time64 *dadate, time64 val)
1968 {
1969  xaccTransBeginEdit(trans);
1970 
1971 #if 0 /* gnc_ctime is expensive so change to 1 only if you need to debug setting
1972  * dates. */
1973  {
1974  time64 secs = (time64) val.tv_sec;
1975  gchar *tstr = gnc_ctime (&secs);
1976  PINFO ("addr=%p set date to %" G_GUINT64_FORMAT ".%09ld %s\n",
1977  trans, val.tv_sec, val.tv_nsec, tstr ? tstr : "(null)");
1978  g_free(tstr);
1979  }
1980 #endif
1981  *dadate = val;
1982  qof_instance_set_dirty(QOF_INSTANCE(trans));
1983  mark_trans(trans);
1984  xaccTransCommitEdit(trans);
1985 
1986  /* Because the date has changed, we need to make sure that each of
1987  * the splits is properly ordered in each of their accounts. We
1988  * could do that here, simply by reinserting each split into its
1989  * account. However, in some ways this is bad behaviour, and it
1990  * seems much better/nicer to defer that until the commit phase,
1991  * i.e. until the user has called the xaccTransCommitEdit()
1992  * routine. So, for now, we are done. */
1993 }
1994 
1995 static inline void
1996 set_gains_date_dirty (Transaction *trans)
1997 {
1998  FOR_EACH_SPLIT(trans, s->gains |= GAINS_STATUS_DATE_DIRTY);
1999 }
2000 
2001 void
2002 xaccTransSetDatePostedSecs (Transaction *trans, time64 secs)
2003 {
2004  if (!trans) return;
2005  xaccTransSetDateInternal(trans, &trans->date_posted, secs);
2006  set_gains_date_dirty(trans);
2007 }
2008 
2009 void
2011 {
2012  GDate date;
2013  gnc_gdate_set_time64(&date, time);
2014  xaccTransSetDatePostedGDate(trans, date);
2015 }
2016 
2017 void
2018 xaccTransSetDatePostedGDate (Transaction *trans, GDate date)
2019 {
2020  GValue v = G_VALUE_INIT;
2021  if (!trans) return;
2022 
2023  /* We additionally save this date into a kvp frame to ensure in
2024  * the future a date which was set as *date* (without time) can
2025  * clearly be distinguished from the time64. */
2026  g_value_init (&v, G_TYPE_DATE);
2027  g_value_set_static_boxed (&v, &date);
2028  qof_instance_set_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_DATE_POSTED);
2029  g_value_unset (&v);
2030  /* mark dirty and commit handled by SetDateInternal */
2031  xaccTransSetDateInternal(trans, &trans->date_posted,
2032  gdate_to_time64(date));
2033  set_gains_date_dirty (trans);
2034 }
2035 
2036 void
2037 xaccTransSetDateEnteredSecs (Transaction *trans, time64 secs)
2038 {
2039  if (!trans) return;
2040  xaccTransSetDateInternal(trans, &trans->date_entered, secs);
2041 }
2042 
2043 void
2044 xaccTransSetDate (Transaction *trans, int day, int mon, int year)
2045 {
2046  GDate *date;
2047  if (!trans) return;
2048  date = g_date_new_dmy(day, mon, year);
2049  if (!g_date_valid(date))
2050  {
2051  PWARN("Attempted to set invalid date %d-%d-%d; set today's date instead.",
2052  year, mon, day);
2053  g_free(date);
2054  date = gnc_g_date_new_today();
2055  }
2056  xaccTransSetDatePostedGDate(trans, *date);
2057  g_free(date);
2058 }
2059 
2060 void
2061 xaccTransSetDateDue (Transaction * trans, time64 time)
2062 {
2063  GValue v = G_VALUE_INIT;
2064  if (!trans) return;
2065  g_value_init (&v, GNC_TYPE_TIME64);
2066  g_value_set_static_boxed (&v, &time);
2067  xaccTransBeginEdit(trans);
2068  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_DUE_KVP);
2069  qof_instance_set_dirty(QOF_INSTANCE(trans));
2070  g_value_unset (&v);
2071  xaccTransCommitEdit(trans);
2072 }
2073 
2074 void
2075 xaccTransSetTxnType (Transaction *trans, char type)
2076 {
2077  char s[2] = {type, '\0'};
2078  GValue v = G_VALUE_INIT;
2079  g_return_if_fail(trans);
2080  g_value_init (&v, G_TYPE_STRING);
2081  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP);
2082  if (!g_strcmp0 (s, g_value_get_string (&v)))
2083  {
2084  g_value_unset (&v);
2085  return;
2086  }
2087  g_value_set_static_string (&v, s);
2088  xaccTransBeginEdit(trans);
2089  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP);
2090  qof_instance_set_dirty(QOF_INSTANCE(trans));
2091  g_value_unset (&v);
2092  xaccTransCommitEdit(trans);
2093 }
2094 
2095 void xaccTransClearReadOnly (Transaction *trans)
2096 {
2097  if (trans)
2098  {
2099  xaccTransBeginEdit(trans);
2100  qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, TRANS_READ_ONLY_REASON);
2101  qof_instance_set_dirty(QOF_INSTANCE(trans));
2102  xaccTransCommitEdit(trans);
2103  }
2104 }
2105 
2106 void
2107 xaccTransSetReadOnly (Transaction *trans, const char *reason)
2108 {
2109  if (trans && reason)
2110  {
2111  GValue v = G_VALUE_INIT;
2112  g_value_init (&v, G_TYPE_STRING);
2113  g_value_set_static_string (&v, reason);
2114  xaccTransBeginEdit(trans);
2115  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_READ_ONLY_REASON);
2116  qof_instance_set_dirty(QOF_INSTANCE(trans));
2117  g_value_unset (&v);
2118  xaccTransCommitEdit(trans);
2119  }
2120 }
2121 
2122 /********************************************************************\
2123 \********************************************************************/
2124 
2125 /* QOF does not open the trans before setting a parameter,
2126 but the call uses check_open so we cannot use the call directly. */
2127 static void
2128 qofTransSetNum (Transaction *trans, const char *xnum)
2129 {
2130  if (!qof_begin_edit(&trans->inst)) return;
2131  xaccTransSetNum(trans, xnum);
2132  qof_commit_edit(&trans->inst);
2133 }
2134 
2135 void
2136 xaccTransSetNum (Transaction *trans, const char *xnum)
2137 {
2138  if (!trans || !xnum) return;
2139  xaccTransBeginEdit(trans);
2140 
2141  CACHE_REPLACE(trans->num, xnum);
2142  qof_instance_set_dirty(QOF_INSTANCE(trans));
2143  mark_trans(trans); /* Dirty balance of every account in trans */
2144  xaccTransCommitEdit(trans);
2145 }
2146 
2147 static void
2148 qofTransSetDescription (Transaction *trans, const char *desc)
2149 {
2150  if (!qof_begin_edit(&trans->inst)) return;
2151  xaccTransSetDescription(trans, desc);
2152  qof_commit_edit(&trans->inst);
2153 }
2154 
2155 void
2156 xaccTransSetDescription (Transaction *trans, const char *desc)
2157 {
2158  if (!trans || !desc) return;
2159  xaccTransBeginEdit(trans);
2160 
2161  CACHE_REPLACE(trans->description, desc);
2162  qof_instance_set_dirty(QOF_INSTANCE(trans));
2163  xaccTransCommitEdit(trans);
2164 }
2165 
2166 void
2167 xaccTransSetDocLink (Transaction *trans, const char *doclink)
2168 {
2169  if (!trans || !doclink) return;
2170 
2171  xaccTransBeginEdit(trans);
2172  if (doclink[0] == '\0')
2173  {
2174  qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, doclink_uri_str);
2175  }
2176  else
2177  {
2178  GValue v = G_VALUE_INIT;
2179  g_value_init (&v, G_TYPE_STRING);
2180  g_value_set_static_string (&v, doclink); //Gets copied at the other end
2181  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, doclink_uri_str);
2182  g_value_unset (&v);
2183  }
2184  qof_instance_set_dirty(QOF_INSTANCE(trans));
2185  xaccTransCommitEdit(trans);
2186 }
2187 
2188 static void
2189 qofTransSetNotes (Transaction *trans, const char *notes)
2190 {
2191  if (!qof_begin_edit(&trans->inst)) return;
2192  xaccTransSetNotes(trans, notes);
2193  qof_commit_edit(&trans->inst);
2194 }
2195 
2196 void
2197 xaccTransSetNotes (Transaction *trans, const char *notes)
2198 {
2199  GValue v = G_VALUE_INIT;
2200  if (!trans || !notes) return;
2201  g_value_init (&v, G_TYPE_STRING);
2202  g_value_set_static_string (&v, notes);
2203  xaccTransBeginEdit(trans);
2204  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
2205  qof_instance_set_dirty(QOF_INSTANCE(trans));
2206  g_value_unset (&v);
2207  xaccTransCommitEdit(trans);
2208 }
2209 
2210 void
2211 xaccTransSetIsClosingTxn (Transaction *trans, gboolean is_closing)
2212 {
2213  if (!trans) return;
2214  xaccTransBeginEdit(trans);
2215 
2216  if (is_closing)
2217  {
2218  GValue v = G_VALUE_INIT;
2219  g_value_init (&v, G_TYPE_INT64);
2220  g_value_set_int64 (&v, 1);
2221  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_is_closing_str);
2222  g_value_unset (&v);
2223  }
2224  else
2225  {
2226  qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, trans_is_closing_str);
2227  }
2228  qof_instance_set_dirty(QOF_INSTANCE(trans));
2229  xaccTransCommitEdit(trans);
2230 }
2231 
2232 
2233 /********************************************************************\
2234 \********************************************************************/
2235 void
2236 xaccTransClearSplits(Transaction* trans)
2237 {
2238  xaccTransBeginEdit(trans);
2239  FOR_EACH_SPLIT(trans, xaccSplitDestroy(s));
2240  g_list_free (trans->splits);
2241  trans->splits = NULL;
2242  xaccTransCommitEdit(trans);
2243 }
2244 
2245 Split *
2246 xaccTransGetSplit (const Transaction *trans, int i)
2247 {
2248  int j = 0;
2249  if (!trans || i < 0) return NULL;
2250 
2251  FOR_EACH_SPLIT(trans, { if (i == j) return s; j++; });
2252  return NULL;
2253 }
2254 
2255 int
2256 xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
2257 {
2258  int j = 0;
2259  g_return_val_if_fail(trans && split, -1);
2260 
2261  FOR_EACH_SPLIT(trans, { if (s == split) return j; j++; });
2262  return -1;
2263 }
2264 
2265 SplitList *
2266 xaccTransGetSplitList (const Transaction *trans)
2267 {
2268  return trans ? trans->splits : NULL;
2269 }
2270 
2271 SplitList *
2272 xaccTransGetPaymentAcctSplitList (const Transaction *trans)
2273 {
2274  GList *pay_splits = NULL;
2275  FOR_EACH_SPLIT (trans,
2276  const Account *account = xaccSplitGetAccount(s);
2277  if (account && gncBusinessIsPaymentAcctType(xaccAccountGetType(account)))
2278  pay_splits = g_list_prepend (pay_splits, s);
2279  );
2280 
2281  pay_splits = g_list_reverse (pay_splits);
2282  return pay_splits;
2283 }
2284 
2285 SplitList *
2286 xaccTransGetAPARAcctSplitList (const Transaction *trans, gboolean strict)
2287 {
2288  GList *apar_splits = NULL;
2289  if (!trans) return NULL;
2290 
2291  FOR_EACH_SPLIT (trans,
2292  const Account *account = xaccSplitGetAccount(s);
2293  if (account && xaccAccountIsAPARType(xaccAccountGetType(account)))
2294  {
2295 
2296  if (!strict)
2297  apar_splits = g_list_prepend (apar_splits, s);
2298  else
2299  {
2300  GncOwner owner;
2301  GNCLot *lot = xaccSplitGetLot(s);
2302  if (lot &&
2303  (gncInvoiceGetInvoiceFromLot (lot) ||
2304  gncOwnerGetOwnerFromLot (lot, &owner)))
2305  apar_splits = g_list_prepend (apar_splits, s);
2306  }
2307  }
2308  );
2309 
2310  apar_splits = g_list_reverse (apar_splits);
2311  return apar_splits;
2312 }
2313 
2314 Split *xaccTransGetFirstPaymentAcctSplit(const Transaction *trans)
2315 {
2316  FOR_EACH_SPLIT (trans,
2317  const Account *account = xaccSplitGetAccount(s);
2318  if (account && gncBusinessIsPaymentAcctType(xaccAccountGetType(account)))
2319  return s;
2320  );
2321 
2322  return NULL;
2323 }
2324 
2325 Split *xaccTransGetFirstAPARAcctSplit (const Transaction *trans, gboolean strict)
2326 {
2327  FOR_EACH_SPLIT (trans,
2328  const Account *account = xaccSplitGetAccount(s);
2329  if (account && xaccAccountIsAPARType(xaccAccountGetType(account)))
2330  {
2331  GNCLot *lot;
2332  GncOwner owner;
2333 
2334  if (!strict)
2335  return s;
2336 
2337  lot = xaccSplitGetLot(s);
2338  if (lot &&
2339  (gncInvoiceGetInvoiceFromLot (lot) ||
2340  gncOwnerGetOwnerFromLot (lot, &owner)))
2341  return s;
2342  }
2343  );
2344 
2345  return NULL;
2346 }
2347 
2348 int
2349 xaccTransCountSplits (const Transaction *trans)
2350 {
2351  gint i = 0;
2352  g_return_val_if_fail (trans != NULL, 0);
2353  FOR_EACH_SPLIT(trans, i++);
2354  return i;
2355 }
2356 
2357 const char *
2358 xaccTransGetNum (const Transaction *trans)
2359 {
2360  return trans ? trans->num : NULL;
2361 }
2362 
2363 const char *
2364 xaccTransGetDescription (const Transaction *trans)
2365 {
2366  return trans ? trans->description : NULL;
2367 }
2368 
2369 const char *
2370 xaccTransGetDocLink (const Transaction *trans)
2371 {
2372  g_return_val_if_fail (trans, NULL);
2373 
2374  GValue v = G_VALUE_INIT;
2375  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, doclink_uri_str);
2376  const char* doclink = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
2377  g_value_unset (&v);
2378 
2379  return doclink;
2380 }
2381 
2382 const char *
2383 xaccTransGetNotes (const Transaction *trans)
2384 {
2385  g_return_val_if_fail (trans, NULL);
2386 
2387  GValue v = G_VALUE_INIT;
2388  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
2389  const char *notes = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
2390  g_value_unset (&v);
2391 
2392  return notes;
2393 }
2394 
2395 gboolean
2396 xaccTransGetIsClosingTxn (const Transaction *trans)
2397 {
2398  if (!trans) return FALSE;
2399 
2400  GValue v = G_VALUE_INIT;
2401  gboolean rv;
2402  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, trans_is_closing_str);
2403  if (G_VALUE_HOLDS_INT64 (&v))
2404  rv = (g_value_get_int64 (&v) ? 1 : 0);
2405  else
2406  rv = 0;
2407  g_value_unset (&v);
2408 
2409  return rv;
2410 }
2411 
2412 /********************************************************************\
2413 \********************************************************************/
2414 
2415 time64
2416 xaccTransGetDate (const Transaction *trans)
2417 {
2418  return trans ? trans->date_posted : 0;
2419 }
2420 
2421 /*################## Added for Reg2 #################*/
2422 time64
2423 xaccTransGetDateEntered (const Transaction *trans)
2424 {
2425  return trans ? trans->date_entered : 0;
2426 }
2427 /*################## Added for Reg2 #################*/
2428 
2429 time64
2430 xaccTransRetDatePosted (const Transaction *trans)
2431 {
2432  return trans ? trans->date_posted : 0;
2433 }
2434 
2435 GDate
2436 xaccTransGetDatePostedGDate (const Transaction *trans)
2437 {
2438  GDate result;
2439  g_date_clear (&result, 1);
2440  if (trans)
2441  {
2442  /* Can we look up this value in the kvp slot? If yes, use it
2443  * from there because it doesn't suffer from time zone
2444  * shifts. */
2445  GValue v = G_VALUE_INIT;
2446  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_POSTED);
2447  if (G_VALUE_HOLDS_BOXED (&v))
2448  result = *(GDate*)g_value_get_boxed (&v);
2449  g_value_unset (&v);
2450  if (! g_date_valid (&result) || gdate_to_time64 (result) == INT64_MAX)
2451  {
2452  /* Well, this txn doesn't have a valid GDate saved in a slot.
2453  * time64_to_gdate() uses local time and we want UTC so we have
2454  * to write it out.
2455  */
2456  time64 time = xaccTransGetDate(trans);
2457  struct tm *stm = gnc_gmtime(&time);
2458  if (stm)
2459  {
2460  g_date_set_dmy(&result, stm->tm_mday,
2461  (GDateMonth)(stm->tm_mon + 1),
2462  stm->tm_year + 1900);
2463  free(stm);
2464  }
2465  }
2466  }
2467  return result;
2468 }
2469 
2470 time64
2471 xaccTransRetDateEntered (const Transaction *trans)
2472 {
2473  return trans ? trans->date_entered : 0;
2474 }
2475 
2476 time64
2477 xaccTransRetDateDue(const Transaction *trans)
2478 {
2479  time64 ret = 0;
2480  GValue v = G_VALUE_INIT;
2481  if (!trans) return 0;
2482  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_DUE_KVP);
2483  if (G_VALUE_HOLDS_BOXED (&v))
2484  {
2485  ret = ((Time64*)g_value_get_boxed (&v))->t;
2486  g_value_unset (&v);
2487  }
2488  if (!ret)
2489  return xaccTransRetDatePosted (trans);
2490  return ret;
2491 }
2492 
2493 char
2494 xaccTransGetTxnType (Transaction *trans)
2495 {
2496  gboolean has_nonAPAR_split = FALSE;
2497 
2498  if (!trans) return TXN_TYPE_NONE;
2499 
2500  if (trans->txn_type != TXN_TYPE_UNCACHED)
2501  return trans->txn_type;
2502 
2503  trans->txn_type = TXN_TYPE_NONE;
2504  for (GList *n = xaccTransGetSplitList (trans); n; n = g_list_next (n))
2505  {
2506  Account *acc = xaccSplitGetAccount (n->data);
2507 
2508  if (!acc)
2509  continue;
2510 
2512  has_nonAPAR_split = TRUE;
2513  else if (trans->txn_type == TXN_TYPE_NONE)
2514  {
2515  GNCLot *lot = xaccSplitGetLot (n->data);
2516  GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
2517  GncOwner owner;
2518 
2519  if (invoice && trans == gncInvoiceGetPostedTxn (invoice))
2520  trans->txn_type = TXN_TYPE_INVOICE;
2521  else if (invoice || gncOwnerGetOwnerFromLot (lot, &owner))
2522  trans->txn_type = TXN_TYPE_PAYMENT;
2523  }
2524  }
2525 
2526  if (!has_nonAPAR_split && (trans->txn_type == TXN_TYPE_PAYMENT))
2527  trans->txn_type = TXN_TYPE_LINK;
2528 
2529  return trans->txn_type;
2530 }
2531 
2532 const char *
2533 xaccTransGetReadOnly (Transaction *trans)
2534 {
2535  if (!trans)
2536  return NULL;
2537 
2538  GValue v = G_VALUE_INIT;
2539  qof_instance_get_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_READ_ONLY_REASON);
2540  const char *readonly_reason = G_VALUE_HOLDS_STRING (&v) ?
2541  g_value_get_string (&v) : NULL;
2542  g_value_unset (&v);
2543  return readonly_reason;
2544 }
2545 
2546 static gboolean
2547 xaccTransIsSXTemplate (const Transaction * trans)
2548 {
2549  Split *split0 = xaccTransGetSplit (trans, 0);
2550  if (split0 != NULL)
2551  {
2552  char* formula = NULL;
2553  g_object_get (split0, "sx-debit-formula", &formula, NULL);
2554  if (formula != NULL)
2555  {
2556  g_free (formula);
2557  return TRUE;
2558  }
2559  g_object_get (split0, "sx-credit-formula", &formula, NULL);
2560  if (formula != NULL)
2561  {
2562  g_free (formula);
2563  return TRUE;
2564  }
2565  }
2566  return FALSE;
2567 }
2568 
2569 gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
2570 {
2571  GDate *threshold_date;
2572  GDate trans_date;
2573  const QofBook *book = xaccTransGetBook (trans);
2574  gboolean result;
2575  g_assert(trans);
2576 
2577  if (!qof_book_uses_autoreadonly(book))
2578  {
2579  return FALSE;
2580  }
2581 
2582  if (xaccTransIsSXTemplate (trans))
2583  return FALSE;
2584 
2585  threshold_date = qof_book_get_autoreadonly_gdate(book);
2586  g_assert(threshold_date); // ok because we checked uses_autoreadonly before
2587  trans_date = xaccTransGetDatePostedGDate(trans);
2588 
2589 // g_warning("there is auto-read-only with days=%d, trans_date_day=%d, threshold_date_day=%d",
2590 // qof_book_get_num_days_autofreeze(book),
2591 // g_date_get_day(&trans_date),
2592 // g_date_get_day(threshold_date));
2593 
2594  if (g_date_compare(&trans_date, threshold_date) < 0)
2595  {
2596  //g_warning("we are auto-read-only");
2597  result = TRUE;
2598  }
2599  else
2600  {
2601  result = FALSE;
2602  }
2603  g_date_free(threshold_date);
2604  return result;
2605 }
2606 
2607 /*################## Added for Reg2 #################*/
2608 
2609 gboolean xaccTransInFutureByPostedDate (const Transaction *trans)
2610 {
2611  time64 present;
2612  gboolean result;
2613  g_assert(trans);
2614 
2615  present = gnc_time64_get_today_end ();
2616 
2617  if (trans->date_posted > present)
2618  result = TRUE;
2619  else
2620  result = FALSE;
2621 
2622  return result;
2623 }
2624 
2625 /*################## Added for Reg2 #################*/
2626 
2627 gboolean
2628 xaccTransHasReconciledSplitsByAccount (const Transaction *trans,
2629  const Account *account)
2630 {
2631  GList *node;
2632 
2633  for (node = xaccTransGetSplitList (trans); node; node = node->next)
2634  {
2635  Split *split = node->data;
2636 
2637  if (!xaccTransStillHasSplit(trans, split))
2638  continue;
2639  if (account && (xaccSplitGetAccount(split) != account))
2640  continue;
2641 
2642  switch (xaccSplitGetReconcile (split))
2643  {
2644  case YREC:
2645  case FREC:
2646  return TRUE;
2647 
2648  default:
2649  break;
2650  }
2651  }
2652 
2653  return FALSE;
2654 }
2655 
2656 gboolean
2657 xaccTransHasReconciledSplits (const Transaction *trans)
2658 {
2659  return xaccTransHasReconciledSplitsByAccount (trans, NULL);
2660 }
2661 
2662 
2663 gboolean
2664 xaccTransHasSplitsInStateByAccount (const Transaction *trans,
2665  const char state,
2666  const Account *account)
2667 {
2668  GList *node;
2669 
2670  for (node = xaccTransGetSplitList (trans); node; node = node->next)
2671  {
2672  Split *split = node->data;
2673 
2674  if (!xaccTransStillHasSplit(trans, split))
2675  continue;
2676  if (account && (xaccSplitGetAccount(split) != account))
2677  continue;
2678 
2679  if (split->reconciled == state)
2680  return TRUE;
2681  }
2682 
2683  return FALSE;
2684 }
2685 
2686 gboolean
2687 xaccTransHasSplitsInState (const Transaction *trans, const char state)
2688 {
2689  return xaccTransHasSplitsInStateByAccount (trans, state, NULL);
2690 }
2691 
2692 
2693 /********************************************************************\
2694 \********************************************************************/
2695 
2696 
2697 /* ====================================================================== */
2698 
2699 static int
2700 counter_thunk(Transaction *t, void *data)
2701 {
2702  (*((guint*)data))++;
2703  return 0;
2704 }
2705 
2706 guint
2708 {
2709  guint count = 0;
2710  xaccAccountTreeForEachTransaction(gnc_book_get_root_account(book),
2711  counter_thunk, (void*)&count);
2712  return count;
2713 }
2714 
2715 /********************************************************************\
2716 \********************************************************************/
2717 
2718 void
2719 xaccTransVoid(Transaction *trans, const char *reason)
2720 {
2721  GValue v = G_VALUE_INIT;
2722  char iso8601_str[ISO_DATELENGTH + 1] = "";
2723 
2724  g_return_if_fail(trans && reason);
2725 
2726  /* Prevent voiding transactions that are already marked
2727  * read only, for example generated by the business features.
2728  */
2729  if (xaccTransGetReadOnly (trans))
2730  {
2731  PWARN ("Refusing to void a read-only transaction!");
2732  return;
2733  }
2734  xaccTransBeginEdit(trans);
2735  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
2736  if (G_VALUE_HOLDS_STRING (&v))
2737  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, void_former_notes_str);
2738  else
2739  g_value_init (&v, G_TYPE_STRING);
2740 
2741  g_value_set_static_string (&v, _("Voided transaction"));
2742  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
2743  g_value_set_static_string (&v, reason);
2744  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
2745 
2746  gnc_time64_to_iso8601_buff (gnc_time(NULL), iso8601_str);
2747  g_value_set_static_string (&v, iso8601_str);
2748  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, void_time_str);
2749  g_value_unset (&v);
2750 
2751  FOR_EACH_SPLIT(trans, xaccSplitVoid(s));
2752 
2753  /* Dirtying taken care of by SetReadOnly */
2754  xaccTransSetReadOnly(trans, _("Transaction Voided"));
2755  xaccTransCommitEdit(trans);
2756 }
2757 
2758 gboolean
2759 xaccTransGetVoidStatus(const Transaction *trans)
2760 {
2761  const char *s = xaccTransGetVoidReason (trans);
2762  return (s && *s);
2763 }
2764 
2765 const char *
2766 xaccTransGetVoidReason(const Transaction *trans)
2767 {
2768  g_return_val_if_fail (trans, NULL);
2769 
2770  GValue v = G_VALUE_INIT;
2771  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
2772  const char *void_reason = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
2773  g_value_unset (&v);
2774 
2775  return void_reason;
2776 }
2777 
2778 time64
2779 xaccTransGetVoidTime(const Transaction *tr)
2780 {
2781  GValue v = G_VALUE_INIT;
2782  const char *s = NULL;
2783  time64 void_time = 0;
2784 
2785  g_return_val_if_fail(tr, void_time);
2786  qof_instance_get_kvp (QOF_INSTANCE (tr), &v, 1, void_time_str);
2787  if (G_VALUE_HOLDS_STRING (&v))
2788  {
2789  s = g_value_get_string (&v);
2790  if (s)
2791  void_time = gnc_iso8601_to_time64_gmt (s);
2792  }
2793  g_value_unset (&v);
2794  return void_time;
2795 }
2796 
2797 void
2798 xaccTransUnvoid (Transaction *trans)
2799 {
2800  GValue v = G_VALUE_INIT;
2801  const char *s = NULL;
2802  g_return_if_fail(trans);
2803 
2804  s = xaccTransGetVoidReason (trans);
2805  if (s == NULL) return; /* Transaction isn't voided. Bail. */
2806  xaccTransBeginEdit(trans);
2807 
2808  qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_former_notes_str);
2809  if (G_VALUE_HOLDS_STRING (&v))
2810  qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
2811  qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, void_former_notes_str);
2812  qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, void_reason_str);
2813  qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, void_time_str);
2814  g_value_unset (&v);
2815 
2816  FOR_EACH_SPLIT(trans, xaccSplitUnvoid(s));
2817 
2818  /* Dirtying taken care of by ClearReadOnly */
2819  xaccTransClearReadOnly(trans);
2820  xaccTransCommitEdit(trans);
2821 }
2822 
2823 Transaction *
2824 xaccTransReverse (Transaction *orig)
2825 {
2826  Transaction *trans;
2827  GValue v = G_VALUE_INIT;
2828  g_return_val_if_fail(orig, NULL);
2829 
2830  /* First edit, dirty, and commit orig to ensure that any trading
2831  * splits are correctly balanced.
2832  */
2833  xaccTransBeginEdit (orig);
2834  qof_instance_set_dirty (QOF_INSTANCE (orig));
2835  xaccTransCommitEdit (orig);
2836 
2837  trans = xaccTransClone(orig);
2838  g_return_val_if_fail (trans, NULL);
2839  xaccTransBeginEdit(trans);
2840 
2841  /* Reverse the values on each split. Clear per-split info. */
2842  FOR_EACH_SPLIT(trans,
2843  {
2847  });
2848 
2849  /* Now update the original with a pointer to the new one */
2850  g_value_init (&v, GNC_TYPE_GUID);
2851  g_value_set_static_boxed (&v, xaccTransGetGUID(trans));
2852  qof_instance_set_kvp (QOF_INSTANCE (orig), &v, 1, TRANS_REVERSED_BY);
2853  g_value_unset (&v);
2854 
2855  /* Make sure the reverse transaction is not read-only */
2856  xaccTransClearReadOnly(trans);
2857 
2858  qof_instance_set_dirty(QOF_INSTANCE(trans));
2859  xaccTransCommitEdit(trans);
2860  return trans;
2861 }
2862 
2863 Transaction *
2864 xaccTransGetReversedBy(const Transaction *trans)
2865 {
2866  GValue v = G_VALUE_INIT;
2867  Transaction *retval = NULL;
2868  g_return_val_if_fail(trans, NULL);
2869  qof_instance_get_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_REVERSED_BY);
2870  if (G_VALUE_HOLDS_BOXED (&v))
2871  {
2872  GncGUID* guid = g_value_get_boxed (&v);
2873  retval = xaccTransLookup(guid, qof_instance_get_book (trans));
2874  }
2875  g_value_unset (&v);
2876  return retval;
2877 }
2878 
2879 /* ============================================================== */
2892 static void
2893 xaccTransScrubGainsDate (Transaction *trans)
2894 {
2895  SplitList *node;
2896  SplitList *splits_copy = g_list_copy(trans->splits);
2897  for (node = splits_copy; node; node = node->next)
2898  {
2899  Split *s = node->data;
2900 
2901  if (!xaccTransStillHasSplit(trans, s)) continue;
2902  xaccSplitDetermineGainStatus(s);
2903 
2904  if ((GAINS_STATUS_GAINS & s->gains) &&
2905  s->gains_split &&
2906  ((s->gains_split->gains & GAINS_STATUS_DATE_DIRTY) ||
2907  (s->gains & GAINS_STATUS_DATE_DIRTY)))
2908  {
2909  Transaction *source_trans = s->gains_split->parent;
2910  s->gains &= ~GAINS_STATUS_DATE_DIRTY;
2911  s->gains_split->gains &= ~GAINS_STATUS_DATE_DIRTY;
2912  xaccTransSetDatePostedSecs(trans, source_trans->date_posted);
2913  FOR_EACH_SPLIT(trans, s->gains &= ~GAINS_STATUS_DATE_DIRTY);
2914  }
2915  }
2916  g_list_free(splits_copy);
2917 }
2918 
2919 /* ============================================================== */
2920 
2921 void
2922 xaccTransScrubGains (Transaction *trans, Account *gain_acc)
2923 {
2924  SplitList *node;
2925 
2926  ENTER("(trans=%p)", trans);
2927  /* Lock down posted date, its to be synced to the posted date
2928  * for the source of the cap gains. */
2929  xaccTransScrubGainsDate(trans);
2930 
2931  /* Fix up the split amount */
2932 restart:
2933  for (node = trans->splits; node; node = node->next)
2934  {
2935  Split *s = node->data;
2936 
2937  if (!xaccTransStillHasSplit(trans, s)) continue;
2938 
2939  xaccSplitDetermineGainStatus(s);
2940  if (s->gains & GAINS_STATUS_ADIRTY)
2941  {
2942  gboolean altered = FALSE;
2943  s->gains &= ~GAINS_STATUS_ADIRTY;
2944  if (s->lot)
2945  altered = xaccScrubLot(s->lot);
2946  else
2947  altered = xaccSplitAssign(s);
2948  if (altered) goto restart;
2949  }
2950  }
2951 
2952  /* Fix up gains split value */
2953  FOR_EACH_SPLIT(trans,
2954  if ((s->gains & GAINS_STATUS_VDIRTY) ||
2955  (s->gains_split &&
2956  (s->gains_split->gains & GAINS_STATUS_VDIRTY)))
2957  xaccSplitComputeCapGains(s, gain_acc);
2958  );
2959 
2960  LEAVE("(trans=%p)", trans);
2961 }
2962 
2963 Split *
2964 xaccTransFindSplitByAccount(const Transaction *trans, const Account *acc)
2965 {
2966  if (!trans || !acc) return NULL;
2967  FOR_EACH_SPLIT(trans, if (xaccSplitGetAccount(s) == acc) return s);
2968  return NULL;
2969 }
2970 
2971 static void
2972 record_price (Split *split,
2973  PriceSource source)
2974 {
2975  Transaction *trans;
2976  Account *account;
2977  QofBook* book;
2978  GNCPriceDB* pricedb;
2979  gnc_commodity* comm;
2980  gnc_commodity* curr;
2981  GNCPrice* price;
2982  gnc_numeric price_value, value, amount;
2983  int scu;
2984  time64 time;
2985  gboolean swap;
2986 
2987  account = xaccSplitGetAccount (split);
2988  if (!xaccAccountIsPriced (account))
2989  {
2990  return;
2991  }
2992  amount = xaccSplitGetAmount (split);
2993  if (gnc_numeric_zero_p (amount))
2994  {
2995  return;
2996  }
2997  trans = xaccSplitGetParent (split);
2998  value = gnc_numeric_div (xaccSplitGetValue (split), amount,
3001  book = qof_instance_get_book (QOF_INSTANCE (account));
3002  pricedb = gnc_pricedb_get_db (book);
3003  comm = xaccAccountGetCommodity (account);
3004  curr = xaccTransGetCurrency (trans);
3005  scu = gnc_commodity_get_fraction (curr);
3006  swap = FALSE;
3007  time = xaccTransGetDate (trans);
3008  price = gnc_pricedb_lookup_day_t64 (pricedb, comm, curr, time);
3009  if (gnc_commodity_equiv (comm, gnc_price_get_currency (price)))
3010  swap = TRUE;
3011 
3012  if (price)
3013  {
3014  PriceSource oldsource = gnc_price_get_source (price);
3015  price_value = gnc_price_get_value (price);
3016  if (gnc_numeric_equal (swap ? gnc_numeric_invert (value) : value,
3017  price_value))
3018  {
3019  gnc_price_unref (price);
3020  return;
3021  }
3022  if (oldsource < source &&
3023  !(oldsource == PRICE_SOURCE_XFER_DLG_VAL &&
3024  source == PRICE_SOURCE_SPLIT_REG))
3025  {
3026  /* Existing price is preferred over this one. */
3027  gnc_price_unref (price);
3028  return;
3029  }
3030  if (swap)
3031  {
3032  value = gnc_numeric_invert (value);
3033  scu = gnc_commodity_get_fraction (comm);
3034  }
3035  value = gnc_numeric_convert (value, scu * COMMODITY_DENOM_MULT,
3037  gnc_price_begin_edit (price);
3038  gnc_price_set_time64 (price, time);
3039  gnc_price_set_source (price, source);
3040  gnc_price_set_typestr (price, PRICE_TYPE_TRN);
3041  gnc_price_set_value (price, value);
3042  gnc_price_commit_edit (price);
3043  gnc_price_unref (price);
3044  return;
3045  }
3046 
3047  value = gnc_numeric_convert (value, scu * COMMODITY_DENOM_MULT,
3049  price = gnc_price_create (book);
3050  gnc_price_begin_edit (price);
3051  gnc_price_set_commodity (price, comm);
3052  gnc_price_set_currency (price, curr);
3053  gnc_price_set_time64 (price, time);
3054  gnc_price_set_source (price, source);
3055  gnc_price_set_typestr (price, PRICE_TYPE_TRN);
3056  gnc_price_set_value (price, value);
3057  gnc_pricedb_add_price (pricedb, price);
3058  gnc_price_commit_edit (price);
3059 }
3060 
3061 void
3062 xaccTransRecordPrice (Transaction *trans, PriceSource source)
3063 {
3064  /* XXX: This should have been part of xaccSplitCommitEdit. */
3065  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
3066  record_price (n->data, source);
3067 }
3068 
3069 /********************************************************************\
3070 \********************************************************************/
3071 /* QofObject function implementation */
3072 
3073 static void
3074 destroy_tx_on_book_close(QofInstance *ent, gpointer data)
3075 {
3076  Transaction* tx = GNC_TRANSACTION(ent);
3077 
3078  xaccTransDestroy(tx);
3079 }
3080 
3085 static void
3086 gnc_transaction_book_end(QofBook* book)
3087 {
3088  QofCollection *col;
3089 
3090  col = qof_book_get_collection(book, GNC_ID_TRANS);
3091  qof_collection_foreach(col, destroy_tx_on_book_close, NULL);
3092 }
3093 
3094 #ifdef _MSC_VER
3095 /* MSVC compiler doesn't have C99 "designated initializers"
3096  * so we wrap them in a macro that is empty on MSVC. */
3097 # define DI(x) /* */
3098 #else
3099 # define DI(x) x
3100 #endif
3101 
3102 /* Hook into the QofObject registry */
3103 static QofObject trans_object_def =
3104 {
3105  DI(.interface_version = ) QOF_OBJECT_VERSION,
3106  DI(.e_type = ) GNC_ID_TRANS,
3107  DI(.type_label = ) "Transaction",
3108  DI(.create = ) (gpointer)xaccMallocTransaction,
3109  DI(.book_begin = ) NULL,
3110  DI(.book_end = ) gnc_transaction_book_end,
3111  DI(.is_dirty = ) qof_collection_is_dirty,
3112  DI(.mark_clean = ) qof_collection_mark_clean,
3113  DI(.foreach = ) qof_collection_foreach,
3114  DI(.printable = ) (const char * (*)(gpointer)) xaccTransGetDescription,
3115  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
3116 };
3117 
3118 static gboolean
3119 trans_is_balanced_p (const Transaction *trans)
3120 {
3121  return trans ? xaccTransIsBalanced(trans) : FALSE;
3122 }
3123 
3124 gboolean xaccTransRegister (void)
3125 {
3126  static QofParam params[] =
3127  {
3128  {
3129  TRANS_NUM, QOF_TYPE_STRING,
3131  (QofSetterFunc)qofTransSetNum,
3133  },
3134  {
3135  TRANS_DESCRIPTION, QOF_TYPE_STRING,
3137  (QofSetterFunc)qofTransSetDescription
3138  },
3139  {
3140  TRANS_DATE_ENTERED, QOF_TYPE_DATE,
3143  },
3144  {
3145  TRANS_DATE_POSTED, QOF_TYPE_DATE,
3148  },
3149  {
3150  TRANS_DATE_DUE, QOF_TYPE_DATE,
3152  },
3153  {
3154  TRANS_IMBALANCE, QOF_TYPE_NUMERIC,
3156  },
3157  {
3158  TRANS_NOTES, QOF_TYPE_STRING,
3160  (QofSetterFunc)qofTransSetNotes
3161  },
3162  {
3163  TRANS_DOCLINK, QOF_TYPE_STRING,
3166  },
3167  {
3168  TRANS_IS_CLOSING, QOF_TYPE_BOOLEAN,
3170  },
3171  {
3172  TRANS_IS_BALANCED, QOF_TYPE_BOOLEAN,
3173  (QofAccessFunc)trans_is_balanced_p, NULL
3174  },
3175  {
3176  TRANS_TYPE, QOF_TYPE_CHAR,
3179  },
3180  {
3181  TRANS_VOID_STATUS, QOF_TYPE_BOOLEAN,
3183  },
3184  {
3185  TRANS_VOID_REASON, QOF_TYPE_STRING,
3187  },
3188  {
3189  TRANS_VOID_TIME, QOF_TYPE_DATE,
3191  },
3192  {
3193  TRANS_SPLITLIST, GNC_ID_SPLIT,
3195  },
3196  {
3197  QOF_PARAM_BOOK, QOF_ID_BOOK,
3199  },
3200  {
3201  QOF_PARAM_GUID, QOF_TYPE_GUID,
3203  },
3204  { NULL },
3205  };
3206 
3207  qof_class_register (GNC_ID_TRANS, (QofSortFunc)xaccTransOrder, params);
3208 
3209  return qof_object_register (&trans_object_def);
3210 }
3211 
3213 _utest_trans_fill_functions (void)
3214 {
3215  TransTestFunctions *func = g_new (TransTestFunctions, 1);
3216 
3217  func->mark_trans = mark_trans;
3218  func->gen_event_trans = gen_event_trans;
3219  func->xaccFreeTransaction = xaccFreeTransaction;
3220  func->destroy_gains = destroy_gains;
3221  func->do_destroy = do_destroy;
3222  func->was_trans_emptied = was_trans_emptied;
3223  func->trans_on_error = trans_on_error;
3224  func->trans_cleanup_commit = trans_cleanup_commit;
3225  func->xaccTransScrubGainsDate = xaccTransScrubGainsDate;
3226  func->dupe_trans = dupe_trans;
3227  return func;
3228 }
3229 
3230 /************************ END OF ************************************\
3231 \************************* FILE *************************************/
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
GNCPrice * gnc_pricedb_lookup_day_t64(GNCPriceDB *db, const gnc_commodity *c, const gnc_commodity *currency, time64 t)
Return the price between the two commodities on the indicated day.
time64 gnc_iso8601_to_time64_gmt(const gchar *)
The gnc_iso8601_to_time64_gmt() routine converts an ISO-8601 style date/time string to time64...
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
Never round at all, and signal an error if there is a fractional result in a computation.
Definition: gnc-numeric.h:179
commit of object update failed because another user has deleted the object
Definition: qofbackend.h:77
GNCPrice * gnc_price_create(QofBook *book)
gnc_price_create - returns a newly allocated and initialized price with a reference count of 1...
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
Traverse all of the transactions in the given account group.
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition: Split.c:1506
High-Level API for imposing Lot constraints.
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
FIXME: document me.
Definition: Transaction.c:2657
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:501
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
Definition: Transaction.c:2010
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
void xaccTransClearSplits(Transaction *trans)
Remove all splits from the transaction.
Definition: Transaction.c:2236
Business Interface: Object OWNERs.
gboolean xaccTransHasSplitsInStateByAccount(const Transaction *trans, const char state, const Account *account)
FIXME: document me.
Definition: Transaction.c:2664
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
Definition: Transaction.c:2246
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2416
void qof_instance_set_kvp(QofInstance *, GValue const *value, unsigned count,...)
Sets a KVP slot to a value from a GValue.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
Definition: Transaction.c:1015
void qof_instance_set_guid(gpointer ptr, const GncGUID *guid)
Set the GncGUID of this instance.
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction is read-only because its posted-date is older than the "auto-readonl...
Definition: Transaction.c:2569
Date and Time handling routines.
#define qof_instance_is_dirty
Return value of is_dirty flag.
Definition: qofinstance.h:166
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4717
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:254
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
Definition: Transaction.c:1872
gnc_numeric xaccTransGetAccountBalance(const Transaction *trans, const Account *account)
Get the account balance for the specified account after the last split in the specified transaction...
Definition: Transaction.c:1310
char xaccTransGetTxnType(Transaction *trans)
Returns the Transaction Type: note this type will be derived from the transaction splits...
Definition: Transaction.c:2494
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:212
#define TXN_TYPE_INVOICE
Transaction is an invoice.
Definition: Transaction.h:126
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3258
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.c:1476
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2680
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
Definition: Transaction.c:2197
const char * xaccTransGetVoidReason(const Transaction *trans)
Returns the user supplied textual reason why a transaction was voided.
Definition: Transaction.c:2766
void xaccTransWriteLog(Transaction *trans, char flag)
Definition: TransLog.c:223
void gnc_price_unref(GNCPrice *p)
gnc_price_unref - indicate you&#39;re finished with a price (i.e.
void qof_backend_set_error(QofBackend *qof_be, QofBackendError err)
Set the error on the specified QofBackend.
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
Definition: Transaction.c:2533
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
void xaccSplitCopyOnto(const Split *from_split, Split *to_split)
This is really a helper for xaccTransCopyOnto.
Definition: Split.c:637
gboolean gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p)
Add a price to the pricedb.
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
commit of object update failed because another user has modified the object
Definition: qofbackend.h:75
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition: qofclass.cpp:86
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split...
Definition: cap-gains.c:528
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
Definition: Transaction.c:2156
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
void xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly, see &#39;gnc_set_num_action&#39; in engine/engine-helpers.c & .h which takes a user-set book option for selecting the source for the num-cell (the transaction-number or the split-action field) in registers/reports into account automatically.
Definition: Transaction.c:2136
void xaccTransRecordPrice(Transaction *trans, PriceSource source)
The xaccTransRecordPrice() method iterates through the splits and and record the non-currency equival...
Definition: Transaction.c:3062
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccTransCopyOnto(const Transaction *from_trans, Transaction *to_trans)
Copy a transaction to another using the function below without changing any account information...
Definition: Transaction.c:720
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:173
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:190
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:222
gboolean xaccTransIsBalanced(const Transaction *trans)
Returns true if the transaction is balanced according to the rules currently in effect.
Definition: Transaction.c:1124
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:64
const char * xaccTransGetNum(const Transaction *trans)
Gets the transaction Number (or ID) field; rather than use this function directly, see &#39;gnc_get_num_action&#39; and &#39;gnc_get_action_num&#39; in engine/engine-helpers.c & .h which takes a user-set book option for selecting the source for the num-cell (the transaction-number or the split-action field) in registers/reports into account automatically.
Definition: Transaction.c:2358
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
gboolean gncBusinessIsPaymentAcctType(GNCAccountType type)
Returns whether the given account type is a valid type to use in business payments.
Definition: gncBusiness.c:92
int xaccTransOrder_num_action(const Transaction *ta, const char *actna, const Transaction *tb, const char *actnb)
The xaccTransOrder_num_action(ta,actna,tb,actnb) method is useful for sorting.
Definition: Transaction.c:1916
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gnc_numeric xaccSplitGetBalance(const Split *s)
Returns the running balance up to and including the indicated split.
Definition: Split.c:1301
Split * xaccTransGetFirstPaymentAcctSplit(const Transaction *trans)
The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first split in this transacti...
Definition: Transaction.c:2314
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:109
QofBackendError qof_backend_get_error(QofBackend *qof_be)
Get the last backend error.
void xaccTransSetDatePostedGDate(Transaction *trans, GDate date)
This method modifies posted date of the transaction, specified by a GDate.
Definition: Transaction.c:2018
void qof_collection_foreach(const QofCollection *col, QofInstanceForeachCB cb_func, gpointer user_data)
Call the callback for each entity in the collection.
Definition: qofid.cpp:320
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:184
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
Retrieves the contents of a KVP slot into a provided GValue.
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
Definition: Transaction.c:2370
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gboolean xaccTransHasReconciledSplitsByAccount(const Transaction *trans, const Account *account)
FIXME: document me.
Definition: Transaction.c:2628
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1407
Account used to record multiple commodity transactions.
Definition: Account.h:155
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Definition: Transaction.c:1458
gboolean xaccSplitEqual(const Split *sa, const Split *sb, gboolean check_guids, gboolean check_balances, gboolean check_txn_splits)
Equality.
Definition: Split.c:772
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
const char * xaccTransGetNotes(const Transaction *trans)
Gets the transaction Notes.
Definition: Transaction.c:2383
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1024
void xaccTransSetIsClosingTxn(Transaction *trans, gboolean is_closing)
Sets whether or not this transaction is a "closing transaction".
Definition: Transaction.c:2211
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
MonetaryList * gnc_monetary_list_delete_zeros(MonetaryList *list)
Delete all entries in the list that have zero value.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2349
void xaccTransSetTxnType(Transaction *trans, char type)
Set the Transaction Type: note the type will be saved into the Transaction kvp property as a backward...
Definition: Transaction.c:2075
#define TXN_TYPE_NONE
No transaction type.
Definition: Transaction.h:125
convert single-entry accounts to clean double-entry
gnc_numeric gnc_numeric_invert(gnc_numeric num)
Invert a gnc_numeric.
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition: qofbook.cpp:988
gboolean xaccTransHasSplitsInState(const Transaction *trans, const char state)
FIXME: document me.
Definition: Transaction.c:2687
guint32 qof_instance_get_idata(gconstpointer inst)
get the instance tag number used for kvp management in sql backends.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_guids, gboolean check_splits, gboolean check_balances, gboolean assume_ordered)
Equality.
Definition: Transaction.c:856
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments &#39;...
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:197
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
The xaccTransGetImbalanceValue() method returns the total value of the transaction.
Definition: Transaction.c:1036
void xaccTransSetReadOnly(Transaction *trans, const char *reason)
Set the transaction to be ReadOnly by setting a non-NULL value as "reason".
Definition: Transaction.c:2107
void xaccTransVoid(Transaction *trans, const char *reason)
xaccTransVoid voids a transaction.
Definition: Transaction.c:2719
Transaction * xaccTransClone(const Transaction *from)
The xaccTransClone() method will create a complete copy of an existing transaction.
Definition: Transaction.c:672
#define YREC
The Split has been reconciled.
Definition: Split.h:72
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
#define FREC
frozen into accounting period
Definition: Split.h:73
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code)
Create a gnc_numeric object that signals the error condition noted by error_code, rather than a numbe...
void gnc_monetary_list_free(MonetaryList *list)
Free a MonetaryList and all the monetaries it points to.
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Correct transaction imbalances.
Definition: Scrub.c:835
void qof_instance_copy_book(gpointer ptr1, gconstpointer ptr2)
Copy the book from one QofInstances to another.
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2430
void xaccTransCopyFromClipBoard(const Transaction *from_trans, Transaction *to_trans, const Account *from_acc, Account *to_acc, gboolean no_date)
This function explicitly must robustly handle some unusual input.
Definition: Transaction.c:744
void xaccTransScrubGains(Transaction *trans, Account *gain_acc)
The xaccTransScrubGains() routine performs a number of cleanup functions on the indicated transaction...
Definition: Transaction.c:2922
Transaction * xaccTransCloneNoKvp(const Transaction *from)
The xaccTransCloneNoKvp() method will create a complete copy of an existing transaction except that ...
Definition: Transaction.c:635
gboolean xaccTransInFutureByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction&#39;s posted-date is in the future.
Definition: Transaction.c:2609
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Definition: Transaction.c:2364
Argument is not a valid number.
Definition: gnc-numeric.h:226
– Business Helper Functions
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1252
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
gboolean gncOwnerGetOwnerFromLot(GNCLot *lot, GncOwner *owner)
Get the owner from the lot.
Definition: gncOwner.c:636
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:177
#define xaccTransGetBook(X)
Definition: Transaction.h:802
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4693
void xaccTransSetDate(Transaction *trans, int day, int mon, int year)
The xaccTransSetDate() method does the same thing as xaccTransSetDate[Posted]Secs(), but takes a convenient day-month-year format.
Definition: Transaction.c:2044
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition: gnc-date.h:108
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:260
void xaccTransSetDateDue(Transaction *trans, time64 time)
Dates and txn-type for A/R and A/P "invoice" postings.
Definition: Transaction.c:2061
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Definition: Transaction.c:1635
Additional event handling code.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
#define xaccSplitGetGUID(X)
Definition: Split.h:555
#define GNC_INVOICE_ID
STRING CONSTANTS ********************************************** Used to declare constant KVP keys use...
Definition: gnc-engine.h:257
#define TXN_TYPE_LINK
Transaction is a link between (invoice and payment) lots.
Definition: Transaction.h:128
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
Definition: Transaction.c:1436
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
Definition: Transaction.c:2256
SplitList * xaccTransGetAPARAcctSplitList(const Transaction *trans, gboolean strict)
The xaccTransGetAPARSplitList() method returns a GList of the splits in a transaction that belong to ...
Definition: Transaction.c:2286
void xaccTransUnvoid(Transaction *trans)
xaccTransUnvoid restores a voided transaction to its original state.
Definition: Transaction.c:2798
#define TXN_TYPE_PAYMENT
Transaction is a payment.
Definition: Transaction.h:127
All type declarations for the whole Gnucash engine.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
time64 xaccTransGetVoidTime(const Transaction *tr)
Returns the time that a transaction was voided.
Definition: Transaction.c:2779
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
#define xaccTransGetGUID(X)
Definition: Transaction.h:804
time64 xaccTransGetDateEntered(const Transaction *trans)
Retrieve the date of when the transaction was entered.
Definition: Transaction.c:2423
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Given a LOT, find and return the Invoice attached to the lot.
Definition: gncInvoice.c:1289
API for the transaction logger.
Business Invoice Interface.
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
Retrieve the &#39;print&#39; name for the specified commodity.
Transaction * xaccTransReverse(Transaction *orig)
xaccTransReverse creates a Transaction that reverses the given transaction by inverting all the numer...
Definition: Transaction.c:2824
guint gnc_book_count_transactions(QofBook *book)
Definition: Transaction.c:2707
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction, specified by a time64 (see ctime(3)).
Definition: Transaction.c:2002
Split * xaccTransGetFirstAPARAcctSplit(const Transaction *trans, gboolean strict)
The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first split in this transacti...
Definition: Transaction.c:2325
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
Definition: Transaction.c:2759
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:497
gboolean xaccSplitAssign(Split *split)
The`xaccSplitAssign() routine will take the indicated split and, if it doesn&#39;t already belong to a lo...
Definition: cap-gains.c:428
SplitList * xaccTransGetPaymentAcctSplitList(const Transaction *trans)
The xaccTransGetPaymentAcctSplitList() method returns a GList of the splits in a transaction that bel...
Definition: Transaction.c:2272
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
void qof_event_suspend(void)
Suspend all engine events.
Definition: qofevent.cpp:145
int qof_string_number_compare_func(gpointer a, gpointer b, gint options, QofParam *getter)
Compare two parameter(strings) as if they are numbers! the two objects, a and b, are the objects bein...
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
Definition: gnc-date.cpp:1243
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3443
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
gboolean xaccTransGetIsClosingTxn(const Transaction *trans)
Returns whether this transaction is a "closing transaction".
Definition: Transaction.c:2396
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1348
This is the private header for the account structure.
void qof_event_resume(void)
Resume engine event generation.
Definition: qofevent.cpp:156
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
Definition: gnc-date.cpp:1355
MonetaryList * xaccTransGetImbalance(const Transaction *trans)
The xaccTransGetImbalance method returns a list giving the value of the transaction in each currency ...
Definition: Transaction.c:1052
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
Definition: Transaction.c:2167
PriceSource
Price source enum.
Definition: gnc-pricedb.h:169
Transaction * xaccTransGetReversedBy(const Transaction *trans)
Returns the transaction that reversed the given transaction.
Definition: Transaction.c:2864
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gboolean xaccScrubLot(GNCLot *lot)
The xaccScrubLot() routine makes sure that the indicated lot is self-consistent and properly balanced...
Definition: Scrub3.c:85
struct tm * gnc_gmtime(const time64 *secs)
fill out a time struct from a 64-bit time value
Definition: gnc-date.cpp:177
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
Retrieve the &#39;unique&#39; name for the specified commodity.
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:167
void xaccSplitSetSharePrice(Split *s, gnc_numeric price)
Definition: Split.c:1191
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
int xaccTransOrder(const Transaction *ta, const Transaction *tb)
The xaccTransOrder(ta,tb) method is useful for sorting.
Definition: Transaction.c:1880
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:521
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:299
char * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition: gnc-date.cpp:255
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2037
time64 xaccTransRetDateEntered(const Transaction *trans)
Retrieve the date of when the transaction was entered.
Definition: Transaction.c:2471
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:962
QofBackend * qof_book_get_backend(const QofBook *book)
Retrieve the backend used by this book.
Definition: qofbook.cpp:440
gboolean qof_book_shutting_down(const QofBook *book)
Is the book shutting down?
Definition: qofbook.cpp:447
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
void xaccTransSortSplits(Transaction *trans)
Sorts the splits in a transaction, putting the debits first, followed by the credits.
Definition: Transaction.c:557
Scheduled Transactions public handling routines.
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2436
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:247
The type used to store guids in C.
Definition: guid.h:75
gboolean qof_book_use_trading_accounts(const QofBook *book)
Returns flag indicating whether this book uses trading accounts.
Definition: qofbook.cpp:909
char * gnc_time64_to_iso8601_buff(time64 time, char *buff)
The gnc_time64_to_iso8601_buff() routine takes the input UTC time64 value and prints it as an ISO-860...
Definition: gnc-date.cpp:1139
Utilities to Automatically Compute Capital Gains/Losses.
time64 xaccTransRetDateDue(const Transaction *trans)
Dates and txn-type for A/R and A/P "invoice" postings.
Definition: Transaction.c:2477
size_t qof_print_date_buff(char *buff, size_t buflen, time64 secs)
Convenience: calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:572
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
Definition: Transaction.c:2266
Commodity handling public routines.
void xaccTransRollbackEdit(Transaction *trans)
The xaccTransRollbackEdit() routine rejects all edits made, and sets the transaction back to where it...
Definition: Transaction.c:1711
Transaction * xaccTransCopyToClipBoard(const Transaction *from_trans)
Copy a transaction to the &#39;clipboard&#39; transaction using dupe_transaction.
Definition: Transaction.c:704
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gnc_numeric xaccTransGetAccountAmount(const Transaction *trans, const Account *acc)
Same as xaccTransGetAccountValue, but uses the Account&#39;s commodity.
Definition: Transaction.c:1186
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn&#39;t be...
Definition: Split.c:1887
gnc_numeric xaccTransGetAccountValue(const Transaction *trans, const Account *acc)
The xaccTransGetAccountValue() method returns the total value applied to a particular account...
Definition: Transaction.c:1170
#define NREC
not reconciled or cleared
Definition: Split.h:74
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69
GDate * gnc_g_date_new_today()
Returns a newly allocated date of the current clock time, taken from time(2).
Definition: gnc-date.cpp:1224