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