GnuCash  4.11-354-g0815ab64c1
Split.c
1 /********************************************************************\
2  * Split.c -- split 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 #ifdef HAVE_SYS_TIME_H
39 # include <sys/time.h>
40 #endif
41 #include <time.h>
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 
46 #include "qof.h"
47 #include "qofbook.h"
48 #include "Split.h"
49 #include "AccountP.h"
50 #include "Scrub.h"
51 #include "TransactionP.h"
52 #include "TransLog.h"
53 #include "cap-gains.h"
54 #include "gnc-commodity.h"
55 #include "gnc-engine.h"
56 #include "gnc-lot.h"
57 #include "gnc-event.h"
58 #include "qofinstance-p.h"
59 
60 const char *void_former_amt_str = "void-former-amount";
61 const char *void_former_val_str = "void-former-value";
62 
63 /* This static indicates the debugging module that this .o belongs to. */
64 static QofLogModule log_module = GNC_MOD_ENGINE;
65 
66 /* KVP key values used for SX info stored Split's slots. */
67 #define GNC_SX_ID "sched-xaction"
68 #define GNC_SX_ACCOUNT "account"
69 #define GNC_SX_CREDIT_FORMULA "credit-formula"
70 #define GNC_SX_DEBIT_FORMULA "debit-formula"
71 #define GNC_SX_CREDIT_NUMERIC "credit-numeric"
72 #define GNC_SX_DEBIT_NUMERIC "debit-numeric"
73 #define GNC_SX_SHARES "shares"
74 
75 enum
76 {
77  PROP_0,
78  PROP_TX, /* Table */
79  PROP_ACCOUNT, /* Table */
80  PROP_MEMO, /* Table */
81  PROP_ACTION, /* Table */
82 // PROP_RECONCILE_STATE, /* Table */
83  PROP_RECONCILE_DATE, /* Table */
84  PROP_VALUE, /* Table, in 2 fields */
85  PROP_SX_ACCOUNT, /* KVP */
86  PROP_SX_CREDIT_FORMULA, /* KVP */
87  PROP_SX_CREDIT_NUMERIC, /* KVP */
88  PROP_SX_DEBIT_FORMULA, /* KVP */
89  PROP_SX_DEBIT_NUMERIC, /* KVP */
90  PROP_SX_SHARES, /* KVP */
91  PROP_LOT, /* KVP */
92  PROP_ONLINE_ACCOUNT, /* KVP */
93  PROP_GAINS_SPLIT, /* KVP */
94  PROP_GAINS_SOURCE, /* KVP */
95  PROP_RUNTIME_0,
96  PROP_AMOUNT, /* Runtime */
97 
98 };
99 
100 static const char * is_unset = "unset";
101 static const char * split_type_normal = "normal";
102 static const char * split_type_stock_split = "stock-split";
103 
104 /* GObject Initialization */
105 G_DEFINE_TYPE(Split, gnc_split, QOF_TYPE_INSTANCE)
106 
107 static void
108 gnc_split_init(Split* split)
109 {
110  /* fill in some sane defaults */
111  split->acc = NULL;
112  split->orig_acc = NULL;
113  split->parent = NULL;
114  split->lot = NULL;
115 
116  split->action = CACHE_INSERT("");
117  split->memo = CACHE_INSERT("");
118  split->reconciled = NREC;
119  split->amount = gnc_numeric_zero();
120  split->value = gnc_numeric_zero();
121 
122  split->date_reconciled = 0;
123  split->split_type = is_unset;
124 
125  split->balance = gnc_numeric_zero();
126  split->cleared_balance = gnc_numeric_zero();
127  split->reconciled_balance = gnc_numeric_zero();
128  split->noclosing_balance = gnc_numeric_zero();
129 
130  split->gains = GAINS_STATUS_UNKNOWN;
131  split->gains_split = NULL;
132 }
133 
134 static void
135 gnc_split_dispose(GObject *splitp)
136 {
137  G_OBJECT_CLASS(gnc_split_parent_class)->dispose(splitp);
138 }
139 
140 static void
141 gnc_split_finalize(GObject* splitp)
142 {
143  G_OBJECT_CLASS(gnc_split_parent_class)->finalize(splitp);
144 }
145 /* Note that g_value_set_object() refs the object, as does
146  * g_object_get(). But g_object_get() only unrefs once when it disgorges
147  * the object, leaving an unbalanced ref, which leaks. So instead of
148  * using g_value_set_object(), use g_value_take_object() which doesn't
149  * ref the object when used in get_property().
150  */
151 static void
152 gnc_split_get_property(GObject *object,
153  guint prop_id,
154  GValue *value,
155  GParamSpec *pspec)
156 {
157  Split *split;
158  gchar *key;
159  Time64 t;
160 
161  g_return_if_fail(GNC_IS_SPLIT(object));
162 
163  split = GNC_SPLIT(object);
164  switch (prop_id)
165  {
166  case PROP_ACTION:
167  g_value_set_string(value, split->action);
168  break;
169  case PROP_MEMO:
170  g_value_set_string(value, split->memo);
171  break;
172  case PROP_VALUE:
173  g_value_set_boxed(value, &split->value);
174  break;
175  case PROP_AMOUNT:
176  g_value_set_boxed(value, &split->amount);
177  break;
178  case PROP_RECONCILE_DATE:
179  t.t = split->date_reconciled;
180  g_value_set_boxed(value, &t);
181  break;
182  case PROP_TX:
183  g_value_take_object(value, split->parent);
184  break;
185  case PROP_ACCOUNT:
186  g_value_take_object(value, split->acc);
187  break;
188  case PROP_LOT:
189  g_value_take_object(value, split->lot);
190  break;
191  case PROP_SX_CREDIT_FORMULA:
192  qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
193  break;
194  case PROP_SX_CREDIT_NUMERIC:
195  qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
196  break;
197  case PROP_SX_DEBIT_FORMULA:
198  qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
199  break;
200  case PROP_SX_DEBIT_NUMERIC:
201  qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
202  break;
203  case PROP_SX_ACCOUNT:
204  qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
205  break;
206  case PROP_SX_SHARES:
207  qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
208  break;
209  case PROP_ONLINE_ACCOUNT:
210  qof_instance_get_kvp (QOF_INSTANCE (split), value, 1, "online_id");
211  break;
212  case PROP_GAINS_SPLIT:
213  qof_instance_get_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
214  break;
215  case PROP_GAINS_SOURCE:
216  qof_instance_get_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
217  break;
218  default:
219  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
220  break;
221  }
222 }
223 
224 static void
225 gnc_split_set_property(GObject *object,
226  guint prop_id,
227  const GValue *value,
228  GParamSpec *pspec)
229 {
230  Split *split;
231  gnc_numeric* number;
232  gchar *key;
233  Time64 *t;
234  g_return_if_fail(GNC_IS_SPLIT(object));
235 
236  split = GNC_SPLIT(object);
237  if (prop_id < PROP_RUNTIME_0 && split->parent != NULL)
238  g_assert (qof_instance_get_editlevel(split->parent));
239 
240  switch (prop_id)
241  {
242  case PROP_ACTION:
243  xaccSplitSetAction(split, g_value_get_string(value));
244  break;
245  case PROP_MEMO:
246  xaccSplitSetMemo(split, g_value_get_string(value));
247  break;
248  case PROP_VALUE:
249  number = g_value_get_boxed(value);
250  xaccSplitSetValue(split, *number);
251  break;
252  case PROP_AMOUNT:
253  number = g_value_get_boxed(value);
254  xaccSplitSetAmount(split, *number);
255  break;
256  case PROP_RECONCILE_DATE:
257  t = g_value_get_boxed(value);
258  xaccSplitSetDateReconciledSecs(split, t->t);
259  break;
260  case PROP_TX:
261  xaccSplitSetParent(split, g_value_get_object(value));
262  break;
263  case PROP_ACCOUNT:
264  xaccSplitSetAccount(split, g_value_get_object(value));
265  break;
266  case PROP_LOT:
267  xaccSplitSetLot(split, g_value_get_object(value));
268  break;
269  case PROP_SX_CREDIT_FORMULA:
270  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
271  break;
272  case PROP_SX_CREDIT_NUMERIC:
273  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
274  break;
275  case PROP_SX_DEBIT_FORMULA:
276  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
277  break;
278  case PROP_SX_DEBIT_NUMERIC:
279  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
280  break;
281  case PROP_SX_ACCOUNT:
282  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
283  break;
284  case PROP_SX_SHARES:
285  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
286  break;
287  case PROP_ONLINE_ACCOUNT:
288  qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "online_id");
289  break;
290  case PROP_GAINS_SPLIT:
291  qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
292  break;
293  case PROP_GAINS_SOURCE:
294  qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
295  break;
296  default:
297  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
298  break;
299  }
300 }
301 
302 static void
303 gnc_split_class_init(SplitClass* klass)
304 {
305  GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
306 
307  gobject_class->dispose = gnc_split_dispose;
308  gobject_class->finalize = gnc_split_finalize;
309  gobject_class->set_property = gnc_split_set_property;
310  gobject_class->get_property = gnc_split_get_property;
311 
312  g_object_class_install_property
313  (gobject_class,
314  PROP_ACTION,
315  g_param_spec_string("action",
316  "Action",
317  "The action is an arbitrary string assigned "
318  "by the user. It is intended to be a short "
319  "string that contains extra information about "
320  "this split.",
321  NULL,
322  G_PARAM_READWRITE));
323 
324  g_object_class_install_property
325  (gobject_class,
326  PROP_MEMO,
327  g_param_spec_string("memo",
328  "Memo",
329  "The action is an arbitrary string assigned "
330  "by the user. It is intended to be a short "
331  "string that describes the purpose of "
332  "this split.",
333  NULL,
334  G_PARAM_READWRITE));
335 
336  g_object_class_install_property
337  (gobject_class,
338  PROP_VALUE,
339  g_param_spec_boxed("value",
340  "Split Value",
341  "The value for this split in the common currency. "
342  "The value and the amount provide enough information to "
343  "calculate a conversion rate.",
344  GNC_TYPE_NUMERIC,
345  G_PARAM_READWRITE));
346 
347  g_object_class_install_property
348  (gobject_class,
349  PROP_AMOUNT,
350  g_param_spec_boxed("amount",
351  "Split Amount",
352  "The value for this split in the currency of its account. "
353  "The value and the amount provide enough information to "
354  "calculate a conversion rate.",
355  GNC_TYPE_NUMERIC,
356  G_PARAM_READWRITE));
357 
358  g_object_class_install_property
359  (gobject_class,
360  PROP_RECONCILE_DATE,
361  g_param_spec_boxed("reconcile-date",
362  "Reconcile Date",
363  "The date this split was reconciled.",
364  GNC_TYPE_TIME64,
365  G_PARAM_READWRITE));
366 
367  g_object_class_install_property
368  (gobject_class,
369  PROP_TX,
370  g_param_spec_object ("transaction",
371  "Transaction",
372  "The transaction that this split belongs to.",
373  GNC_TYPE_TRANSACTION,
374  G_PARAM_READWRITE));
375 
376  g_object_class_install_property
377  (gobject_class,
378  PROP_ACCOUNT,
379  g_param_spec_object ("account",
380  "Account",
381  "The account that this split belongs to.",
382  GNC_TYPE_ACCOUNT,
383  G_PARAM_READWRITE));
384 
385  g_object_class_install_property
386  (gobject_class,
387  PROP_LOT,
388  g_param_spec_object ("lot",
389  "Lot",
390  "The lot that this split belongs to.",
391  GNC_TYPE_LOT,
392  G_PARAM_READWRITE));
393 
394  g_object_class_install_property
395  (gobject_class,
396  PROP_SX_DEBIT_FORMULA,
397  g_param_spec_string("sx-debit-formula",
398  "Schedule Transaction Debit Formula",
399  "The formula used to calculate the actual debit "
400  "amount when a real split is generated from this "
401  "SX split.",
402  NULL,
403  G_PARAM_READWRITE));
404 
405  g_object_class_install_property
406  (gobject_class,
407  PROP_SX_DEBIT_NUMERIC,
408  g_param_spec_boxed("sx-debit-numeric",
409  "Scheduled Transaction Debit Numeric",
410  "Numeric value to plug into the Debit Formula when a "
411  "real split is generated from this SX split.",
412  GNC_TYPE_NUMERIC,
413  G_PARAM_READWRITE));
414 
415  g_object_class_install_property
416  (gobject_class,
417  PROP_SX_CREDIT_FORMULA,
418  g_param_spec_string("sx-credit-formula",
419  "Schedule Transaction Credit Formula",
420  "The formula used to calculate the actual credit "
421  "amount when a real split is generated from this "
422  "SX split.",
423  NULL,
424  G_PARAM_READWRITE));
425 
426  g_object_class_install_property
427  (gobject_class,
428  PROP_SX_CREDIT_NUMERIC,
429  g_param_spec_boxed("sx-credit-numeric",
430  "Scheduled Transaction Credit Numeric",
431  "Numeric value to plug into the Credit Formula when a "
432  "real split is generated from this SX split.",
433  GNC_TYPE_NUMERIC,
434  G_PARAM_READWRITE));
435 /* FIXME: PROP_SX_SHARES should be stored as a gnc_numeric, but the function
436  * which uses it, gnc_template_register_save_shares_cell, stores a
437  * phony string. This is maintained until backwards compatibility can
438  * be established.
439  */
440  g_object_class_install_property
441  (gobject_class,
442  PROP_SX_SHARES,
443  g_param_spec_string("sx-shares",
444  "Scheduled Transaction Shares",
445  "Numeric value of shares to insert in a new split when "
446  "it's generated from this SX split.",
447  NULL,
448  G_PARAM_READWRITE));
449 
450  g_object_class_install_property
451  (gobject_class,
452  PROP_SX_ACCOUNT,
453  g_param_spec_boxed("sx-account",
454  "Scheduled Transaction Account",
455  "The target account for a scheduled transaction split.",
456  GNC_TYPE_GUID,
457  G_PARAM_READWRITE));
458 
459  g_object_class_install_property
460  (gobject_class,
461  PROP_ONLINE_ACCOUNT,
462  g_param_spec_string ("online-id",
463  "Online Account ID",
464  "The online account which corresponds to this "
465  "account for OFX/HCBI import",
466  NULL,
467  G_PARAM_READWRITE));
468 
469  g_object_class_install_property
470  (gobject_class,
471  PROP_GAINS_SPLIT,
472  g_param_spec_boxed ("gains-split",
473  "Gains Split",
474  "The capital gains split associated with this "
475  "split when this split represents the proceeds "
476  "from the sale of a commodity inside a Lot.",
477  GNC_TYPE_GUID,
478  G_PARAM_READWRITE));
479 
480  g_object_class_install_property
481  (gobject_class,
482  PROP_GAINS_SOURCE,
483  g_param_spec_boxed ("gains-source",
484  "Gains Source",
485  "The source split for which this split this is "
486  "the gains split. ",
487  GNC_TYPE_GUID,
488  G_PARAM_READWRITE));
489 }
490 
491 /********************************************************************\
492  * xaccInitSplit
493  * Initialize a Split structure
494 \********************************************************************/
495 
496 static void
497 xaccInitSplit(Split * split, QofBook *book)
498 {
499  qof_instance_init_data(&split->inst, GNC_ID_SPLIT, book);
500 }
501 
502 void
503 xaccSplitReinit(Split * split)
504 {
505  /* fill in some sane defaults */
506  split->acc = NULL;
507  split->orig_acc = NULL;
508  split->parent = NULL;
509  split->lot = NULL;
510 
511  CACHE_REPLACE(split->action, "");
512  CACHE_REPLACE(split->memo, "");
513  split->reconciled = NREC;
514  split->amount = gnc_numeric_zero();
515  split->value = gnc_numeric_zero();
516 
517  split->date_reconciled = 0;
518 
519  split->balance = gnc_numeric_zero();
520  split->cleared_balance = gnc_numeric_zero();
521  split->reconciled_balance = gnc_numeric_zero();
522  split->noclosing_balance = gnc_numeric_zero();
523 
524  qof_instance_set_idata(split, 0);
525 
526  split->gains = GAINS_STATUS_UNKNOWN;
527  split->gains_split = NULL;
528 }
529 
530 /********************************************************************\
531 \********************************************************************/
532 
533 Split *
534 xaccMallocSplit(QofBook *book)
535 {
536  Split *split;
537  g_return_val_if_fail (book, NULL);
538 
539  split = g_object_new (GNC_TYPE_SPLIT, NULL);
540  xaccInitSplit (split, book);
541 
542  return split;
543 }
544 
545 /********************************************************************\
546 \********************************************************************/
547 /* This routine is not exposed externally, since it does weird things,
548  * like not really setting up the parent account correctly, and ditto
549  * the parent transaction. This routine is prone to programmer error
550  * if not used correctly. It is used only by the edit-rollback code.
551  * Don't get duped!
552  */
553 
554 Split *
555 xaccDupeSplit (const Split *s)
556 {
557  Split *split = g_object_new (GNC_TYPE_SPLIT, NULL);
558 
559  /* Trash the entity table. We don't want to mistake the cloned
560  * splits as something official. If we ever use this split, we'll
561  * have to fix this up.
562  */
563  split->inst.e_type = NULL;
564  qof_instance_copy_guid(split, s);
565  qof_instance_copy_book(split, s);
566 
567  split->parent = s->parent;
568  split->acc = s->acc;
569  split->orig_acc = s->orig_acc;
570  split->lot = s->lot;
571 
572  CACHE_REPLACE(split->memo, s->memo);
573  CACHE_REPLACE(split->action, s->action);
574 
575  qof_instance_copy_kvp (QOF_INSTANCE (split), QOF_INSTANCE (s));
576 
577  split->reconciled = s->reconciled;
578  split->date_reconciled = s->date_reconciled;
579 
580  split->value = s->value;
581  split->amount = s->amount;
582 
583  /* no need to futz with the balances; these get wiped each time ...
584  * split->balance = s->balance;
585  * split->cleared_balance = s->cleared_balance;
586  * split->reconciled_balance = s->reconciled_balance;
587  */
588 
589  return split;
590 }
591 
592 Split *
593 xaccSplitCloneNoKvp (const Split *s)
594 {
595  Split *split = g_object_new (GNC_TYPE_SPLIT, NULL);
596 
597  split->parent = NULL;
598  split->memo = CACHE_INSERT(s->memo);
599  split->action = CACHE_INSERT(s->action);
600  split->reconciled = s->reconciled;
601  split->date_reconciled = s->date_reconciled;
602  split->value = s->value;
603  split->amount = s->amount;
604  split->balance = s->balance;
605  split->cleared_balance = s->cleared_balance;
606  split->reconciled_balance = s->reconciled_balance;
607  split->noclosing_balance = s->noclosing_balance;
608 
609  split->gains = GAINS_STATUS_UNKNOWN;
610  split->gains_split = NULL;
611 
612  qof_instance_init_data(&split->inst, GNC_ID_SPLIT,
614  xaccAccountInsertSplit(s->acc, split);
615  if (s->lot)
616  {
617  /* CHECKME: Is this right? */
618  gnc_lot_add_split(s->lot, split);
619  }
620  return split;
621 }
622 
623 void
624 xaccSplitCopyKvp (const Split *from, Split *to)
625 {
626  qof_instance_copy_kvp (QOF_INSTANCE (to), QOF_INSTANCE (from));
627 }
628 
629 /*################## Added for Reg2 #################*/
630 
631 /* This is really a helper for xaccTransCopyOnto. It doesn't reparent
632  the 'to' split to from's transaction, because xaccTransCopyOnto is
633  responsible for parenting the split to the correct transaction.
634  Also, from's parent transaction may not even be a valid
635  transaction, so this function may not modify anything about 'from'
636  or from's transaction.
637 */
638 void
639 xaccSplitCopyOnto(const Split *from_split, Split *to_split)
640 {
641  if (!from_split || !to_split) return;
642  xaccTransBeginEdit (to_split->parent);
643 
644  xaccSplitSetMemo(to_split, xaccSplitGetMemo(from_split));
645  xaccSplitSetAction(to_split, xaccSplitGetAction(from_split));
646  xaccSplitSetAmount(to_split, xaccSplitGetAmount(from_split));
647  xaccSplitSetValue(to_split, xaccSplitGetValue(from_split));
648  /* Setting the account is okay here because, even though the from
649  split might not really belong to the account it claims to,
650  setting the account won't cause any event involving from. */
651  xaccSplitSetAccount(to_split, xaccSplitGetAccount(from_split));
652  /* N.B. Don't set parent. */
653 
654  qof_instance_set_dirty(QOF_INSTANCE(to_split));
655  xaccTransCommitEdit(to_split->parent);
656 }
657 
658 /*################## Added for Reg2 #################*/
659 
660 
661 #ifdef DUMP_FUNCTIONS
662 void
663 xaccSplitDump (const Split *split, const char *tag)
664 {
665  char datebuff[MAX_DATE_LENGTH + 1];
666  memset (datebuff, 0, sizeof(datebuff));
667  qof_print_date_buff (datebuff, MAX_DATE_LENGTH, split->date_reconciled);
668  printf(" %s Split %p", tag, split);
669  printf(" Book: %p\n", qof_instance_get_book(split));
670  printf(" Account: %p (%s)\n", split->acc,
671  split->acc ? xaccAccountGetName(split->acc) : "");
672  printf(" Commod: %s\n",
673  split->acc ?
675  : "");
676  printf(" Lot: %p\n", split->lot);
677  printf(" Parent: %p\n", split->parent);
678  printf(" Gains: %p\n", split->gains_split);
679  printf(" Memo: %s\n", split->memo ? split->memo : "(null)");
680  printf(" Action: %s\n", split->action ? split->action : "(null)");
681  printf(" KVP Data: %s\n", qof_instance_kvp_as_string (QOF_INSTANCE (split)));
682  printf(" Recncld: %c (date %s)\n", split->reconciled, datebuff);
683 
684  printf(" Value: %s\n", gnc_numeric_to_string(split->value));
685  printf(" Amount: %s\n", gnc_numeric_to_string(split->amount));
686  printf(" Balance: %s\n", gnc_numeric_to_string(split->balance));
687  printf(" CBalance: %s\n", gnc_numeric_to_string(split->cleared_balance));
688  printf(" RBalance: %s\n",
689  gnc_numeric_to_string(split->reconciled_balance));
690  printf(" NoClose: %s\n", gnc_numeric_to_string(split->noclosing_balance));
691  printf(" idata: %x\n", qof_instance_get_idata(split));
692 }
693 #endif
694 
695 /********************************************************************\
696 \********************************************************************/
697 
698 void
699 xaccFreeSplit (Split *split)
700 {
701  if (!split) return;
702 
703  /* Debug double-free's */
704  if (((char *) 1) == split->memo)
705  {
706  PERR ("double-free %p", split);
707  return;
708  }
709  CACHE_REMOVE(split->memo);
710  CACHE_REMOVE(split->action);
711 
712  /* Just in case someone looks up freed memory ... */
713  split->memo = (char *) 1;
714  split->action = NULL;
715  split->reconciled = NREC;
716  split->amount = gnc_numeric_zero();
717  split->value = gnc_numeric_zero();
718  split->parent = NULL;
719  split->lot = NULL;
720  split->acc = NULL;
721  split->orig_acc = NULL;
722  split->split_type = NULL;
723 
724  split->date_reconciled = 0;
725  G_OBJECT_CLASS (QOF_INSTANCE_GET_CLASS (&split->inst))->dispose(G_OBJECT (split));
726  // Is this right?
727  if (split->gains_split) split->gains_split->gains_split = NULL;
728  /* qof_instance_release(&split->inst); */
729  g_object_unref(split);
730 }
731 
732 void mark_split (Split *s)
733 {
734  if (s->acc)
735  {
736  g_object_set(s->acc, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
737  }
738 
739  /* set dirty flag on lot too. */
740  if (s->lot) gnc_lot_set_closed_unknown(s->lot);
741 }
742 
743 /*
744  * Helper routine for xaccSplitEqual.
745  */
746 static gboolean
747 xaccSplitEqualCheckBal (const char *tag, gnc_numeric a, gnc_numeric b)
748 {
749  char *str_a, *str_b;
750 
751  if (gnc_numeric_equal (a, b))
752  return TRUE;
753 
754  str_a = gnc_numeric_to_string (a);
755  str_b = gnc_numeric_to_string (b);
756 
757  PINFO ("%sbalances differ: %s vs %s", tag, str_a, str_b);
758 
759  g_free (str_a);
760  g_free (str_b);
761 
762  return FALSE;
763 }
764 
765 /********************************************************************
766  * xaccSplitEqual
767  ********************************************************************/
768 gboolean
769 xaccSplitEqual(const Split *sa, const Split *sb,
770  gboolean check_guids,
771  gboolean check_balances,
772  gboolean check_txn_splits)
773 {
774  gboolean same_book;
775 
776  if (!sa && !sb) return TRUE; /* Arguable. FALSE is better, methinks */
777 
778  if (!sa || !sb)
779  {
780  PINFO ("one is NULL");
781  return FALSE;
782  }
783 
784  if (sa == sb) return TRUE;
785 
786  same_book = qof_instance_get_book(QOF_INSTANCE(sa)) == qof_instance_get_book(QOF_INSTANCE(sb));
787 
788  if (check_guids)
789  {
790  if (qof_instance_guid_compare(sa, sb) != 0)
791  {
792  PINFO ("GUIDs differ");
793  return FALSE;
794  }
795  }
796 
797  /* If the same book, since these strings are cached we can just use pointer equality */
798  if ((same_book && sa->memo != sb->memo) || (!same_book && g_strcmp0(sa->memo, sb->memo) != 0))
799  {
800  PINFO ("memos differ: (%p)%s vs (%p)%s",
801  sa->memo, sa->memo, sb->memo, sb->memo);
802  return FALSE;
803  }
804 
805  if ((same_book && sa->action != sb->action) || (!same_book && g_strcmp0(sa->action, sb->action) != 0))
806  {
807  PINFO ("actions differ: %s vs %s", sa->action, sb->action);
808  return FALSE;
809  }
810 
811  if (qof_instance_compare_kvp (QOF_INSTANCE (sa), QOF_INSTANCE (sb)) != 0)
812  {
813  char *frame_a;
814  char *frame_b;
815 
816  frame_a = qof_instance_kvp_as_string (QOF_INSTANCE (sa));
817  frame_b = qof_instance_kvp_as_string (QOF_INSTANCE (sb));
818 
819  PINFO ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
820 
821  g_free (frame_a);
822  g_free (frame_b);
823 
824  return FALSE;
825  }
826 
827  if (sa->reconciled != sb->reconciled)
828  {
829  PINFO ("reconcile flags differ: %c vs %c", sa->reconciled, sb->reconciled);
830  return FALSE;
831  }
832 
833  if (sa->date_reconciled != sb->date_reconciled)
834  {
835  PINFO ("reconciled date differs");
836  return FALSE;
837  }
838 
840  {
841  char *str_a;
842  char *str_b;
843 
846 
847  PINFO ("amounts differ: %s vs %s", str_a, str_b);
848 
849  g_free (str_a);
850  g_free (str_b);
851 
852  return FALSE;
853  }
854 
856  {
857  char *str_a;
858  char *str_b;
859 
862 
863  PINFO ("values differ: %s vs %s", str_a, str_b);
864 
865  g_free (str_a);
866  g_free (str_b);
867 
868  return FALSE;
869  }
870 
871  if (check_balances)
872  {
873  if (!xaccSplitEqualCheckBal ("", sa->balance, sb->balance))
874  return FALSE;
875  if (!xaccSplitEqualCheckBal ("cleared ", sa->cleared_balance,
876  sb->cleared_balance))
877  return FALSE;
878  if (!xaccSplitEqualCheckBal ("reconciled ", sa->reconciled_balance,
879  sb->reconciled_balance))
880  return FALSE;
881  if (!xaccSplitEqualCheckBal ("noclosing ", sa->noclosing_balance,
882  sb->noclosing_balance))
883  return FALSE;
884  }
885 
886  if (!xaccTransEqual(sa->parent, sb->parent, check_guids, check_txn_splits,
887  check_balances, FALSE))
888  {
889  PINFO ("transactions differ");
890  return FALSE;
891  }
892 
893  return TRUE;
894 }
895 
896 
897 /*################## Added for Reg2 #################*/
898 /********************************************************************
899  * xaccSplitListGetUniqueTransactions
900  ********************************************************************/
901 GList *
902 xaccSplitListGetUniqueTransactionsReversed (const GList *splits)
903 {
904  GHashTable *txn_hash = g_hash_table_new (NULL, NULL);
905  GList *transList = NULL;
906  const GList *snode;
907 
908  for (snode = splits; snode; snode = snode->next)
909  {
910  Transaction *trans = xaccSplitGetParent((Split *)(snode->data));
911 
912  if (g_hash_table_contains (txn_hash, trans))
913  continue;
914 
915  g_hash_table_insert (txn_hash, trans, NULL);
916  transList = g_list_prepend (transList, trans);
917  }
918  g_hash_table_destroy (txn_hash);
919  return transList;
920 }
921 
922 GList *
923 xaccSplitListGetUniqueTransactions(const GList *splits)
924 {
925  return g_list_reverse (xaccSplitListGetUniqueTransactionsReversed (splits));
926 }
927 
928 /*################## Added for Reg2 #################*/
929 
930 
931 /********************************************************************
932  * Account funcs
933  ********************************************************************/
934 
935 Account *
936 xaccSplitGetAccount (const Split *s)
937 {
938  return s ? s->acc : NULL;
939 }
940 
941 void
942 xaccSplitSetAccount (Split *s, Account *acc)
943 {
944  Transaction *trans;
945 
946  g_return_if_fail(s && acc);
947  g_return_if_fail(qof_instance_books_equal(acc, s));
948 
949  trans = s->parent;
950  if (trans)
951  xaccTransBeginEdit(trans);
952 
953  s->acc = acc;
954  qof_instance_set_dirty(QOF_INSTANCE(s));
955 
956  if (trans)
957  xaccTransCommitEdit(trans);
958 }
959 
960 static void commit_err (QofInstance *inst, QofBackendError errcode)
961 {
962  PERR("commit error: %d", errcode);
963  gnc_engine_signal_commit_error( errcode );
964 }
965 
966 /* An engine-private helper for completing xaccTransCommitEdit(). */
967 void
968 xaccSplitCommitEdit(Split *s)
969 {
970  Account *acc = NULL;
971  Account *orig_acc = NULL;
972 
973  g_return_if_fail(s);
974  if (!qof_instance_is_dirty(QOF_INSTANCE(s)))
975  return;
976 
977  orig_acc = s->orig_acc;
978 
979  if (GNC_IS_ACCOUNT(s->acc))
980  acc = s->acc;
981 
982  /* Remove from lot (but only if it hasn't been moved to
983  new lot already) */
984  if (s->lot && (gnc_lot_get_account(s->lot) != acc || qof_instance_get_destroying(s)))
985  gnc_lot_remove_split (s->lot, s);
986 
987  /* Possibly remove the split from the original account... */
988  if (orig_acc && (orig_acc != acc || qof_instance_get_destroying(s)))
989  {
990  if (!gnc_account_remove_split(orig_acc, s))
991  {
992  PERR("Account lost track of moved or deleted split.");
993  }
994  }
995 
996  /* ... and insert it into the new account if needed */
997  if (acc && (orig_acc != acc) && !qof_instance_get_destroying(s))
998  {
999  if (gnc_account_insert_split(acc, s))
1000  {
1001  /* If the split's lot belonged to some other account, we
1002  leave it so. */
1003  if (s->lot && (NULL == gnc_lot_get_account(s->lot)))
1004  xaccAccountInsertLot (acc, s->lot);
1005  }
1006  else
1007  {
1008  PERR("Account grabbed split prematurely.");
1009  }
1011  }
1012 
1013  if (s->parent != s->orig_parent)
1014  {
1015  //FIXME: find better event
1016  if (s->orig_parent)
1017  qof_event_gen(&s->orig_parent->inst, QOF_EVENT_MODIFY,
1018  NULL);
1019  }
1020  if (s->lot)
1021  {
1022  /* A change of value/amnt affects gains display, etc. */
1023  qof_event_gen (QOF_INSTANCE(s->lot), QOF_EVENT_MODIFY, NULL);
1024  }
1025 
1026  /* Important: we save off the original parent transaction and account
1027  so that when we commit, we can generate signals for both the
1028  original and new transactions, for the _next_ begin/commit cycle. */
1029  s->orig_acc = s->acc;
1030  s->orig_parent = s->parent;
1031  if (!qof_commit_edit_part2(QOF_INSTANCE(s), commit_err, NULL,
1032  (void (*) (QofInstance *)) xaccFreeSplit))
1033  return;
1034 
1035  if (acc)
1036  {
1037  g_object_set(acc, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
1039  }
1040 }
1041 
1042 /* An engine-private helper for completing xaccTransRollbackEdit(). */
1043 void
1044 xaccSplitRollbackEdit(Split *s)
1045 {
1046 
1047  /* Don't use setters because we want to allow NULL. This is legit
1048  only because we don't emit events for changing accounts until
1049  the final commit. */
1050  if (s->acc != s->orig_acc)
1051  s->acc = s->orig_acc;
1052 
1053  /* Undestroy if needed */
1054  if (qof_instance_get_destroying(s) && s->parent)
1055  {
1056  GncEventData ed;
1057  qof_instance_set_destroying(s, FALSE);
1058  ed.node = s;
1059  ed.idx = -1; /* unused */
1060  qof_event_gen(&s->parent->inst, GNC_EVENT_ITEM_ADDED, &ed);
1061  }
1062 
1063  /* But for the parent trans, we want the intermediate events, so
1064  we use the setter. */
1065  xaccSplitSetParent(s, s->orig_parent);
1066 }
1067 
1068 /********************************************************************\
1069 \********************************************************************/
1070 
1071 Split *
1072 xaccSplitLookup (const GncGUID *guid, QofBook *book)
1073 {
1074  QofCollection *col;
1075  if (!guid || !book) return NULL;
1076  col = qof_book_get_collection (book, GNC_ID_SPLIT);
1077  return (Split *) qof_collection_lookup_entity (col, guid);
1078 }
1079 
1080 /********************************************************************\
1081 \********************************************************************/
1082 /* Routines for marking splits dirty, and for sending out change
1083  * events. Note that we can't just mark-n-generate-event in one
1084  * step, since sometimes we need to mark things up before its suitable
1085  * to send out a change event.
1086  */
1087 
1088 /* CHECKME: This function modifies the Split without dirtying or
1089  checking its parent. Is that correct? */
1090 void
1091 xaccSplitDetermineGainStatus (Split *split)
1092 {
1093  Split *other;
1094  GValue v = G_VALUE_INIT;
1095  GncGUID *guid = NULL;
1096 
1097  if (GAINS_STATUS_UNKNOWN != split->gains) return;
1098 
1099  other = xaccSplitGetCapGainsSplit (split);
1100  if (other)
1101  {
1102  split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1103  split->gains_split = other;
1104  return;
1105  }
1106 
1107  qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, "gains-source");
1108  if (G_VALUE_HOLDS_BOXED (&v))
1109  guid = (GncGUID*)g_value_get_boxed (&v);
1110  if (!guid)
1111  {
1112  // CHECKME: We leave split->gains_split alone. Is that correct?
1113  split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1114  }
1115  else
1116  {
1117  QofCollection *col;
1119  GNC_ID_SPLIT);
1120  split->gains = GAINS_STATUS_GAINS;
1121  other = (Split *) qof_collection_lookup_entity (col, guid);
1122  split->gains_split = other;
1123  }
1124  g_value_unset (&v);
1125 }
1126 
1127 /********************************************************************\
1128 \********************************************************************/
1129 
1130 static inline int
1131 get_currency_denom(const Split * s)
1132 {
1133  if (!s)
1134  {
1135  return 0;
1136  }
1137  else if (!s->parent || !s->parent->common_currency)
1138  {
1140  }
1141  else
1142  {
1143  return gnc_commodity_get_fraction (s->parent->common_currency);
1144  }
1145 }
1146 
1147 static inline int
1148 get_commodity_denom(const Split * s)
1149 {
1150  if (!s)
1151  {
1152  return 0;
1153  }
1154  else if (!s->acc)
1155  {
1157  }
1158  else
1159  {
1160  return xaccAccountGetCommoditySCU(s->acc);
1161  }
1162 }
1163 
1164 /********************************************************************\
1165 \********************************************************************/
1166 
1167 void
1168 xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)
1169 {
1170  if (!s) return;
1171  ENTER (" ");
1172  xaccTransBeginEdit (s->parent);
1173 
1174  s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1176  s->value = gnc_numeric_mul(s->amount, price,
1177  get_currency_denom(s), GNC_HOW_RND_ROUND_HALF_UP);
1178 
1179  SET_GAINS_A_VDIRTY(s);
1180  mark_split (s);
1181  qof_instance_set_dirty(QOF_INSTANCE(s));
1182  xaccTransCommitEdit(s->parent);
1183  LEAVE ("");
1184 }
1185 
1186 static void
1187 qofSplitSetSharePrice (Split *split, gnc_numeric price)
1188 {
1189  g_return_if_fail(split);
1190  split->value = gnc_numeric_mul(xaccSplitGetAmount(split),
1191  price, get_currency_denom(split),
1193 }
1194 
1195 void
1196 xaccSplitSetSharePrice (Split *s, gnc_numeric price)
1197 {
1198  if (!s) return;
1199 
1200  if (gnc_numeric_zero_p (price))
1201  return;
1202 
1203  ENTER (" ");
1204  xaccTransBeginEdit (s->parent);
1205 
1206  s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
1207  price, get_currency_denom(s),
1209 
1210  SET_GAINS_VDIRTY(s);
1211  mark_split (s);
1212  qof_instance_set_dirty(QOF_INSTANCE(s));
1213  xaccTransCommitEdit(s->parent);
1214  LEAVE ("");
1215 }
1216 
1217 static void
1218 qofSplitSetAmount (Split *split, gnc_numeric amt)
1219 {
1220  g_return_if_fail(split);
1221  if (split->acc)
1222  {
1223  split->amount = gnc_numeric_convert(amt,
1224  get_commodity_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1225  }
1226  else
1227  {
1228  split->amount = amt;
1229  }
1230 }
1231 
1232 /* The amount of the split in the _account's_ commodity. */
1233 void
1234 xaccSplitSetAmount (Split *s, gnc_numeric amt)
1235 {
1236  if (!s) return;
1237  g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1238  ENTER ("(split=%p) old amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1239  " new amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1240  s->amount.num, s->amount.denom, amt.num, amt.denom);
1241 
1242  xaccTransBeginEdit (s->parent);
1243  if (s->acc)
1244  {
1245  s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1247  g_assert (gnc_numeric_check (s->amount) == GNC_ERROR_OK);
1248  }
1249  else
1250  s->amount = amt;
1251 
1252  SET_GAINS_ADIRTY(s);
1253  mark_split (s);
1254  qof_instance_set_dirty(QOF_INSTANCE(s));
1255  xaccTransCommitEdit(s->parent);
1256  LEAVE("");
1257 }
1258 
1259 static void
1260 qofSplitSetValue (Split *split, gnc_numeric amt)
1261 {
1262  g_return_if_fail(split);
1263  split->value = gnc_numeric_convert(amt,
1264  get_currency_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1265  g_assert(gnc_numeric_check (split->value) != GNC_ERROR_OK);
1266 }
1267 
1268 /* The value of the split in the _transaction's_ currency. */
1269 void
1270 xaccSplitSetValue (Split *s, gnc_numeric amt)
1271 {
1272  gnc_numeric new_val;
1273  if (!s) return;
1274 
1275  g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1276  ENTER ("(split=%p) old val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1277  " new val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1278  s->value.num, s->value.denom, amt.num, amt.denom);
1279 
1280  xaccTransBeginEdit (s->parent);
1281  new_val = gnc_numeric_convert(amt, get_currency_denom(s),
1283  if (gnc_numeric_check(new_val) == GNC_ERROR_OK &&
1284  !(gnc_numeric_zero_p (new_val) && !gnc_numeric_zero_p (amt)))
1285  s->value = new_val;
1286  else PERR("numeric error %s in converting the split value's denominator with amount %s and denom %d", gnc_numeric_errorCode_to_string(gnc_numeric_check(new_val)), gnc_numeric_to_string(amt), get_currency_denom(s));
1287 
1288  SET_GAINS_VDIRTY(s);
1289  mark_split (s);
1290  qof_instance_set_dirty(QOF_INSTANCE(s));
1291  xaccTransCommitEdit(s->parent);
1292  LEAVE ("");
1293 }
1294 
1295 /********************************************************************\
1296 \********************************************************************/
1297 
1298 gnc_numeric
1299 xaccSplitGetBalance (const Split *s)
1300 {
1301  return s ? s->balance : gnc_numeric_zero();
1302 }
1303 
1304 gnc_numeric
1306 {
1307  return s ? s->noclosing_balance : gnc_numeric_zero();
1308 }
1309 
1310 gnc_numeric
1312 {
1313  return s ? s->cleared_balance : gnc_numeric_zero();
1314 }
1315 
1316 gnc_numeric
1318 {
1319  return s ? s->reconciled_balance : gnc_numeric_zero();
1320 }
1321 
1322 void
1323 xaccSplitSetBaseValue (Split *s, gnc_numeric value,
1324  const gnc_commodity * base_currency)
1325 {
1326  const gnc_commodity *currency;
1327  const gnc_commodity *commodity;
1328 
1329  if (!s) return;
1330  xaccTransBeginEdit (s->parent);
1331 
1332  if (!s->acc)
1333  {
1334  PERR ("split must have a parent account");
1335  return;
1336  }
1337 
1338  currency = xaccTransGetCurrency (s->parent);
1339  commodity = xaccAccountGetCommodity (s->acc);
1340 
1341  /* If the base_currency is the transaction's commodity ('currency'),
1342  * set the value. If it's the account commodity, set the
1343  * amount. If both, set both. */
1344  if (gnc_commodity_equiv(currency, base_currency))
1345  {
1346  if (gnc_commodity_equiv(commodity, base_currency))
1347  {
1348  s->amount = gnc_numeric_convert(value,
1349  get_commodity_denom(s),
1351  }
1352  s->value = gnc_numeric_convert(value,
1353  get_currency_denom(s),
1355  }
1356  else if (gnc_commodity_equiv(commodity, base_currency))
1357  {
1358  s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
1360  }
1361  else
1362  {
1363  PERR ("inappropriate base currency %s "
1364  "given split currency=%s and commodity=%s\n",
1365  gnc_commodity_get_printname(base_currency),
1366  gnc_commodity_get_printname(currency),
1367  gnc_commodity_get_printname(commodity));
1368  return;
1369  }
1370 
1371  SET_GAINS_A_VDIRTY(s);
1372  mark_split (s);
1373  qof_instance_set_dirty(QOF_INSTANCE(s));
1374  xaccTransCommitEdit(s->parent);
1375 }
1376 
1377 gnc_numeric
1378 xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)
1379 {
1380  if (!s || !s->acc || !s->parent) return gnc_numeric_zero();
1381 
1382  /* be more precise -- the value depends on the currency we want it
1383  * expressed in. */
1384  if (gnc_commodity_equiv(xaccTransGetCurrency(s->parent), base_currency))
1385  return xaccSplitGetValue(s);
1386  if (gnc_commodity_equiv(xaccAccountGetCommodity(s->acc), base_currency))
1387  return xaccSplitGetAmount(s);
1388 
1389  PERR ("inappropriate base currency %s "
1390  "given split currency=%s and commodity=%s\n",
1391  gnc_commodity_get_printname(base_currency),
1394  return gnc_numeric_zero();
1395 }
1396 
1397 /********************************************************************\
1398 \********************************************************************/
1399 
1400 gnc_numeric
1401 xaccSplitConvertAmount (const Split *split, const Account * account)
1402 {
1403  gnc_commodity *acc_com, *to_commodity;
1404  Transaction *txn;
1405  gnc_numeric amount, value, convrate;
1406  Account * split_acc;
1407 
1408  amount = xaccSplitGetAmount (split);
1409 
1410  /* If this split is attached to this account, OR */
1411  split_acc = xaccSplitGetAccount (split);
1412  if (split_acc == account)
1413  return amount;
1414 
1415  /* If split->account->commodity == to_commodity, return the amount */
1416  acc_com = xaccAccountGetCommodity (split_acc);
1417  to_commodity = xaccAccountGetCommodity (account);
1418  if (acc_com && gnc_commodity_equal (acc_com, to_commodity))
1419  return amount;
1420 
1421  /* Ok, this split is not for the viewed account, and the commodity
1422  * does not match. So we need to do some conversion.
1423  *
1424  * First, we can cheat. If this transaction is balanced and has
1425  * exactly two splits, then we can implicitly determine the exchange
1426  * rate and just return the 'other' split amount.
1427  */
1428  txn = xaccSplitGetParent (split);
1429  if (txn && xaccTransIsBalanced (txn))
1430  {
1431  const Split *osplit = xaccSplitGetOtherSplit (split);
1432 
1433  if (osplit)
1434  {
1435  gnc_commodity* split_comm =
1437  if (!gnc_commodity_equal(to_commodity, split_comm))
1438  {
1439  gchar guidstr[GUID_ENCODING_LENGTH+1];
1440  guid_to_string_buff(xaccSplitGetGUID(osplit),guidstr);
1441  PERR("The split's (%s) amount can't be converted from %s into %s.",
1442  guidstr,
1443  gnc_commodity_get_mnemonic(split_comm),
1444  gnc_commodity_get_mnemonic(to_commodity)
1445  );
1446  return gnc_numeric_zero();
1447  }
1448  return gnc_numeric_neg (xaccSplitGetAmount (osplit));
1449  }
1450  }
1451 
1452  /* ... otherwise, we need to compute the amount from the conversion
1453  * rate into _this account_. So, find the split into this account,
1454  * compute the conversion rate (based on amount/value), and then multiply
1455  * this times the split value.
1456  */
1457  value = xaccSplitGetValue (split);
1458 
1459  if (gnc_numeric_zero_p (value))
1460  {
1461  return value;
1462  }
1463 
1464  convrate = xaccTransGetAccountConvRate(txn, account);
1465  return gnc_numeric_mul (value, convrate,
1466  gnc_commodity_get_fraction (to_commodity),
1468 }
1469 
1470 /********************************************************************\
1471 \********************************************************************/
1472 
1473 gboolean
1474 xaccSplitDestroy (Split *split)
1475 {
1476  Account *acc;
1477  Transaction *trans;
1478  GncEventData ed;
1479 
1480  if (!split) return TRUE;
1481 
1482  acc = split->acc;
1483  trans = split->parent;
1484  if (acc && !qof_instance_get_destroying(acc)
1485  && !qof_instance_get_destroying(trans)
1486  && xaccTransGetReadOnly(trans))
1487  return FALSE;
1488 
1489  xaccTransBeginEdit(trans);
1490  ed.node = split;
1491  ed.idx = xaccTransGetSplitIndex(trans, split);
1492  qof_instance_set_dirty(QOF_INSTANCE(split));
1493  qof_instance_set_destroying(split, TRUE);
1494  qof_event_gen(&trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1495  xaccTransCommitEdit(trans);
1496 
1497  return TRUE;
1498 }
1499 
1500 /********************************************************************\
1501 \********************************************************************/
1502 
1503 gint
1504 xaccSplitOrder (const Split *sa, const Split *sb)
1505 {
1506  int retval;
1507  int comp;
1508  const char *da, *db;
1509  gboolean action_for_num;
1510 
1511  if (sa == sb) return 0;
1512  /* nothing is always less than something */
1513  if (!sa) return -1;
1514  if (!sb) return +1;
1515 
1516  /* sort in transaction order, but use split action rather than trans num
1517  * according to book option */
1519  (xaccSplitGetBook (sa));
1520  if (action_for_num)
1521  retval = xaccTransOrder_num_action (sa->parent, sa->action,
1522  sb->parent, sb->action);
1523  else
1524  retval = xaccTransOrder (sa->parent, sb->parent);
1525  if (retval) return retval;
1526 
1527  /* otherwise, sort on memo strings */
1528  da = sa->memo ? sa->memo : "";
1529  db = sb->memo ? sb->memo : "";
1530  retval = g_utf8_collate (da, db);
1531  if (retval)
1532  return retval;
1533 
1534  /* otherwise, sort on action strings */
1535  da = sa->action ? sa->action : "";
1536  db = sb->action ? sb->action : "";
1537  retval = g_utf8_collate (da, db);
1538  if (retval != 0)
1539  return retval;
1540 
1541  /* the reconciled flag ... */
1542  if (sa->reconciled < sb->reconciled) return -1;
1543  if (sa->reconciled > sb->reconciled) return +1;
1544 
1545  /* compare amounts */
1547  if (comp < 0) return -1;
1548  if (comp > 0) return +1;
1549 
1551  if (comp < 0) return -1;
1552  if (comp > 0) return +1;
1553 
1554  /* if dates differ, return */
1555  if (sa->date_reconciled < sb->date_reconciled)
1556  return -1;
1557  else if (sa->date_reconciled > sb->date_reconciled)
1558  return 1;
1559 
1560  /* else, sort on guid - keeps sort stable. */
1561  retval = qof_instance_guid_compare(sa, sb);
1562  if (retval) return retval;
1563 
1564  return 0;
1565 }
1566 
1567 gint
1568 xaccSplitOrderDateOnly (const Split *sa, const Split *sb)
1569 {
1570  Transaction *ta, *tb;
1571 
1572  if (sa == sb) return 0;
1573  /* nothing is always less than something */
1574  if (!sa) return -1;
1575  if (!sb) return +1;
1576 
1577  ta = sa->parent;
1578  tb = sb->parent;
1579  if ( !ta && !tb ) return 0;
1580  if ( !tb ) return -1;
1581  if ( !ta ) return +1;
1582 
1583  if (ta->date_posted == tb->date_posted)
1584  return -1; // Keep the same order
1585  return (ta->date_posted > tb->date_posted) - (ta->date_posted < tb->date_posted);
1586 }
1587 
1588 static gboolean
1589 get_corr_account_split(const Split *sa, const Split **retval)
1590 {
1591  *retval = NULL;
1592  g_return_val_if_fail(sa, FALSE);
1593 
1594  if (xaccTransCountSplits (sa->parent) > 2)
1595  return FALSE;
1596 
1597  *retval = xaccSplitGetOtherSplit (sa);
1598  if (*retval)
1599  return TRUE;
1600  else
1601  return FALSE;
1602 }
1603 
1604 /* TODO: these static consts can be shared. */
1605 const char *
1607 {
1608  static const char *split_const = NULL;
1609  const Split *other_split;
1610 
1611  if (!get_corr_account_split(sa, &other_split))
1612  {
1613  if (!split_const)
1614  split_const = _("-- Split Transaction --");
1615 
1616  return split_const;
1617  }
1618 
1619  return xaccAccountGetName(other_split->acc);
1620 }
1621 
1622 char *
1624 {
1625  static const char *split_const = NULL;
1626  const Split *other_split;
1627 
1628  if (!get_corr_account_split(sa, &other_split))
1629  {
1630  if (!split_const)
1631  split_const = _("-- Split Transaction --");
1632 
1633  return g_strdup(split_const);
1634  }
1635  return gnc_account_get_full_name(other_split->acc);
1636 }
1637 
1638 const char *
1640 {
1641  static const char *split_const = NULL;
1642  const Split *other_split;
1643 
1644  if (!get_corr_account_split(sa, &other_split))
1645  {
1646  if (!split_const)
1647  split_const = C_("Displayed account code of the other account in a multi-split transaction", "Split");
1648 
1649  return split_const;
1650  }
1651  return xaccAccountGetCode(other_split->acc);
1652 }
1653 
1654 /* TODO: It's not too hard to make this function avoid the malloc/free. */
1655 int
1656 xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
1657 {
1658  Account *aa, *ab;
1659  char *full_a, *full_b;
1660  int retval;
1661  if (!sa && !sb) return 0;
1662  if (!sa) return -1;
1663  if (!sb) return 1;
1664 
1665  aa = sa->acc;
1666  ab = sb->acc;
1667  full_a = gnc_account_get_full_name(aa);
1668  full_b = gnc_account_get_full_name(ab);
1669  retval = g_utf8_collate(full_a, full_b);
1670  g_free(full_a);
1671  g_free(full_b);
1672  return retval;
1673 }
1674 
1675 
1676 int
1677 xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
1678 {
1679  Account *aa, *ab;
1680  if (!sa && !sb) return 0;
1681  if (!sa) return -1;
1682  if (!sb) return 1;
1683 
1684  aa = sa->acc;
1685  ab = sb->acc;
1686 
1687  return g_strcmp0(xaccAccountGetCode(aa), xaccAccountGetCode(ab));
1688 }
1689 
1690 int
1691 xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
1692 {
1693  char *ca, *cb;
1694  int retval;
1695  if (!sa && !sb) return 0;
1696  if (!sa) return -1;
1697  if (!sb) return 1;
1698 
1699  /* doesn't matter what separator we use
1700  * as long as they are the same
1701  */
1702 
1705  retval = g_strcmp0(ca, cb);
1706  g_free(ca);
1707  g_free(cb);
1708  return retval;
1709 }
1710 
1711 int
1712 xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
1713 {
1714  const char *ca, *cb;
1715  if (!sa && !sb) return 0;
1716  if (!sa) return -1;
1717  if (!sb) return 1;
1718 
1719  ca = xaccSplitGetCorrAccountCode(sa);
1720  cb = xaccSplitGetCorrAccountCode(sb);
1721  return g_strcmp0(ca, cb);
1722 }
1723 
1724 static void
1725 qofSplitSetMemo (Split *split, const char* memo)
1726 {
1727  g_return_if_fail(split);
1728  CACHE_REPLACE(split->memo, memo);
1729 }
1730 
1731 void
1732 xaccSplitSetMemo (Split *split, const char *memo)
1733 {
1734  if (!split || !memo) return;
1735  xaccTransBeginEdit (split->parent);
1736 
1737  CACHE_REPLACE(split->memo, memo);
1738  qof_instance_set_dirty(QOF_INSTANCE(split));
1739  xaccTransCommitEdit(split->parent);
1740 
1741 }
1742 
1743 static void
1744 qofSplitSetAction (Split *split, const char *actn)
1745 {
1746  g_return_if_fail(split);
1747  CACHE_REPLACE(split->action, actn);
1748 }
1749 
1750 void
1751 xaccSplitSetAction (Split *split, const char *actn)
1752 {
1753  if (!split || !actn) return;
1754  xaccTransBeginEdit (split->parent);
1755 
1756  CACHE_REPLACE(split->action, actn);
1757  qof_instance_set_dirty(QOF_INSTANCE(split));
1758  xaccTransCommitEdit(split->parent);
1759 
1760 }
1761 
1762 static void
1763 qofSplitSetReconcile (Split *split, char recn)
1764 {
1765  g_return_if_fail(split);
1766  switch (recn)
1767  {
1768  case NREC:
1769  case CREC:
1770  case YREC:
1771  case FREC:
1772  case VREC:
1773  split->reconciled = recn;
1774  mark_split (split);
1775  xaccAccountRecomputeBalance (split->acc);
1776  break;
1777  default:
1778  PERR("Bad reconciled flag");
1779  break;
1780  }
1781 }
1782 
1783 void
1784 xaccSplitSetReconcile (Split *split, char recn)
1785 {
1786  if (!split || split->reconciled == recn) return;
1787  xaccTransBeginEdit (split->parent);
1788 
1789  switch (recn)
1790  {
1791  case NREC:
1792  case CREC:
1793  case YREC:
1794  case FREC:
1795  case VREC:
1796  split->reconciled = recn;
1797  mark_split (split);
1798  qof_instance_set_dirty(QOF_INSTANCE(split));
1799  xaccAccountRecomputeBalance (split->acc);
1800  break;
1801  default:
1802  PERR("Bad reconciled flag");
1803  break;
1804  }
1805  xaccTransCommitEdit(split->parent);
1806 
1807 }
1808 
1809 void
1811 {
1812  if (!split) return;
1813  xaccTransBeginEdit (split->parent);
1814 
1815  split->date_reconciled = secs;
1816  qof_instance_set_dirty(QOF_INSTANCE(split));
1817  xaccTransCommitEdit(split->parent);
1818 
1819 }
1820 
1821 
1822 /*################## Added for Reg2 #################*/
1823 time64
1824 xaccSplitGetDateReconciled (const Split * split)
1825 {
1826  return split ? split->date_reconciled : 0;
1827 }
1828 /*################## Added for Reg2 #################*/
1829 
1830 /********************************************************************\
1831 \********************************************************************/
1832 
1833 /* return the parent transaction of the split */
1834 Transaction *
1835 xaccSplitGetParent (const Split *split)
1836 {
1837  return split ? split->parent : NULL;
1838 }
1839 
1840 void
1841 xaccSplitSetParent(Split *s, Transaction *t)
1842 {
1843  Transaction *old_trans;
1844  GncEventData ed;
1845 
1846  g_return_if_fail(s);
1847  if (s->parent == t) return;
1848 
1849  if (s->parent != s->orig_parent && s->orig_parent != t)
1850  PERR("You may not add the split to more than one transaction"
1851  " during the BeginEdit/CommitEdit block.");
1852  xaccTransBeginEdit(t);
1853  old_trans = s->parent;
1854 
1855  xaccTransBeginEdit(old_trans);
1856 
1857  ed.node = s;
1858  if (old_trans)
1859  {
1860  ed.idx = xaccTransGetSplitIndex(old_trans, s);
1861  qof_event_gen(&old_trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1862  }
1863  s->parent = t;
1864 
1865  xaccTransCommitEdit(old_trans);
1866  qof_instance_set_dirty(QOF_INSTANCE(s));
1867 
1868  if (t)
1869  {
1870  /* Convert split to new transaction's commodity denominator */
1872 
1873  /* add ourselves to the new transaction's list of pending splits. */
1874  if (NULL == g_list_find(t->splits, s))
1875  t->splits = g_list_append(t->splits, s);
1876 
1877  ed.idx = -1; /* unused */
1878  qof_event_gen(&t->inst, GNC_EVENT_ITEM_ADDED, &ed);
1879  }
1881 }
1882 
1883 
1884 GNCLot *
1885 xaccSplitGetLot (const Split *split)
1886 {
1887  return split ? split->lot : NULL;
1888 }
1889 
1890 void
1891 xaccSplitSetLot(Split* split, GNCLot* lot)
1892 {
1893  xaccTransBeginEdit (split->parent);
1894  split->lot = lot;
1895  qof_instance_set_dirty(QOF_INSTANCE(split));
1896  xaccTransCommitEdit(split->parent);
1897 }
1898 
1899 const char *
1900 xaccSplitGetMemo (const Split *split)
1901 {
1902  return split ? split->memo : NULL;
1903 }
1904 
1905 const char *
1906 xaccSplitGetAction (const Split *split)
1907 {
1908  return split ? split->action : NULL;
1909 }
1910 
1911 char
1912 xaccSplitGetReconcile (const Split *split)
1913 {
1914  return split ? split->reconciled : ' ';
1915 }
1916 
1917 
1918 gnc_numeric
1919 xaccSplitGetAmount (const Split * split)
1920 {
1921  return split ? split->amount : gnc_numeric_zero();
1922 }
1923 
1924 gnc_numeric
1925 xaccSplitGetValue (const Split * split)
1926 {
1927  return split ? split->value : gnc_numeric_zero();
1928 }
1929 
1930 gnc_numeric
1931 xaccSplitGetSharePrice (const Split * split)
1932 {
1933  gnc_numeric amt, val, price;
1934  if (!split) return gnc_numeric_create(0, 1);
1935 
1936 
1937  /* if amount == 0, return 0
1938  * otherwise return value/amount
1939  */
1940 
1941  amt = xaccSplitGetAmount(split);
1942  val = xaccSplitGetValue(split);
1943  if (gnc_numeric_zero_p(amt))
1944  return gnc_numeric_create(0, 1);
1945 
1946  price = gnc_numeric_div(val, amt,
1949 
1950  /* During random checks we can get some very weird prices. Let's
1951  * handle some overflow and other error conditions by returning
1952  * zero. But still print an error to let us know it happened.
1953  */
1954  if (gnc_numeric_check(price))
1955  {
1956  PERR("Computing share price failed (%d): [ %" G_GINT64_FORMAT " / %"
1957  G_GINT64_FORMAT " ] / [ %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " ]",
1958  gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
1959  return gnc_numeric_create(0, 1);
1960  }
1961 
1962  return price;
1963 }
1964 
1965 /********************************************************************\
1966 \********************************************************************/
1967 
1968 QofBook *
1969 xaccSplitGetBook (const Split *split)
1970 {
1971  return qof_instance_get_book(QOF_INSTANCE(split));
1972 }
1973 
1974 const char *
1975 xaccSplitGetType(const Split *s)
1976 {
1977  if (!s) return NULL;
1978  if (s->split_type == is_unset)
1979  {
1980  GValue v = G_VALUE_INIT;
1981  Split *split = (Split*) s;
1982  const char* type;
1983  qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
1984  type = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
1985  if (!type || !g_strcmp0 (type, split_type_normal))
1986  split->split_type = (char*) split_type_normal;
1987  else if (!g_strcmp0 (type, split_type_stock_split))
1988  split->split_type = (char*) split_type_stock_split;
1989  else
1990  {
1991  PERR ("unexpected split-type %s, reset to normal.", type);
1992  split->split_type = split_type_normal;
1993  }
1994  g_value_unset (&v);
1995  }
1996  return s->split_type;
1997 }
1998 
1999 /* reconfigure a split to be a stock split - after this, you shouldn't
2000  mess with the value, just the amount. */
2001 void
2003 {
2004  GValue v = G_VALUE_INIT;
2005  xaccTransBeginEdit (s->parent);
2006 
2007  s->value = gnc_numeric_zero();
2008  g_value_init (&v, G_TYPE_STRING);
2009  g_value_set_static_string (&v, split_type_stock_split);
2010  s->split_type = split_type_stock_split;
2011  qof_instance_set_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
2012  SET_GAINS_VDIRTY(s);
2013  mark_split(s);
2014  qof_instance_set_dirty(QOF_INSTANCE(s));
2015  xaccTransCommitEdit(s->parent);
2016  g_value_unset (&v);
2017 }
2018 
2019 void
2020 xaccSplitAddPeerSplit (Split *split, const Split *other_split,
2021  time64 timestamp)
2022 {
2023  const GncGUID* guid;
2024 
2025  g_return_if_fail (split != NULL);
2026  g_return_if_fail (other_split != NULL);
2027 
2028  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2029  xaccTransBeginEdit (split->parent);
2030  qof_instance_kvp_add_guid (QOF_INSTANCE (split), "lot-split",
2031  gnc_time(NULL), "peer_guid", guid_copy(guid));
2032  mark_split (split);
2033  qof_instance_set_dirty (QOF_INSTANCE (split));
2034  xaccTransCommitEdit (split->parent);
2035 }
2036 
2037 gboolean
2038 xaccSplitHasPeers (const Split *split)
2039 {
2040  return qof_instance_has_slot (QOF_INSTANCE (split), "lot-split");
2041 }
2042 
2043 gboolean
2044 xaccSplitIsPeerSplit (const Split *split, const Split *other_split)
2045 {
2046  const GncGUID* guid;
2047 
2048  g_return_val_if_fail (split != NULL, FALSE);
2049  g_return_val_if_fail (other_split != NULL, FALSE);
2050 
2051  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2052  return qof_instance_kvp_has_guid (QOF_INSTANCE (split), "lot-split",
2053  "peer_guid", guid);
2054 }
2055 
2056 void
2057 xaccSplitRemovePeerSplit (Split *split, const Split *other_split)
2058 {
2059  const GncGUID* guid;
2060 
2061  g_return_if_fail (split != NULL);
2062  g_return_if_fail (other_split != NULL);
2063 
2064  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2065  xaccTransBeginEdit (split->parent);
2066  qof_instance_kvp_remove_guid (QOF_INSTANCE (split), "lot-split",
2067  "peer_guid", guid);
2068  mark_split (split);
2069  qof_instance_set_dirty (QOF_INSTANCE (split));
2070  xaccTransCommitEdit (split->parent);
2071 }
2072 
2073 void
2074 xaccSplitMergePeerSplits (Split *split, const Split *other_split)
2075 {
2076  xaccTransBeginEdit (split->parent);
2077  qof_instance_kvp_merge_guids (QOF_INSTANCE (split),
2078  QOF_INSTANCE (other_split), "lot-split");
2079  mark_split (split);
2080  qof_instance_set_dirty (QOF_INSTANCE (split));
2081  xaccTransCommitEdit (split->parent);
2082 }
2083 
2084 /********************************************************************\
2085 \********************************************************************/
2086 /* In the old world, the 'other split' was the other split of a
2087  * transaction that contained only two splits. In the new world,
2088  * a split may have been cut up between multiple lots, although
2089  * in a conceptual sense, if lots hadn't been used, there would be
2090  * only a pair. So we handle this conceptual case: we can still
2091  * identify, unambiguously, the 'other' split when 'this' split
2092  * as been cut up across lots. We do this by looking for the
2093  * 'lot-split' keyword, which occurs only in cut-up splits.
2094  */
2095 
2096 Split *
2097 xaccSplitGetOtherSplit (const Split *split)
2098 {
2099  Transaction *trans;
2100  Split *other = NULL;
2101 
2102  if (!split) return NULL;
2103  trans = split->parent;
2104  if (!trans) return NULL;
2105 
2106  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
2107  {
2108  Split *s = n->data;
2109  if ((s == split) ||
2110  (!xaccTransStillHasSplit(trans, s)) ||
2112  (qof_instance_has_slot (QOF_INSTANCE (s), "lot-split")))
2113  continue;
2114 
2115  if (other)
2116  return NULL;
2117 
2118  other = s;
2119  }
2120  return other;
2121 }
2122 
2123 /********************************************************************\
2124 \********************************************************************/
2125 
2126 gnc_numeric
2127 xaccSplitVoidFormerAmount(const Split *split)
2128 {
2129  GValue v = G_VALUE_INIT;
2130  gnc_numeric *num = NULL;
2131  gnc_numeric retval;
2132  g_return_val_if_fail(split, gnc_numeric_zero());
2133  qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
2134  if (G_VALUE_HOLDS_BOXED (&v))
2135  num = (gnc_numeric*)g_value_get_boxed (&v);
2136  retval = num ? *num : gnc_numeric_zero();
2137  g_value_unset (&v);
2138  return retval;
2139 }
2140 
2141 gnc_numeric
2142 xaccSplitVoidFormerValue(const Split *split)
2143 {
2144  GValue v = G_VALUE_INIT;
2145  gnc_numeric *num = NULL;
2146  gnc_numeric retval;
2147  g_return_val_if_fail(split, gnc_numeric_zero());
2148  qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
2149  if (G_VALUE_HOLDS_BOXED (&v))
2150  num = (gnc_numeric*)g_value_get_boxed (&v);
2151  retval = num ? *num : gnc_numeric_zero();
2152  g_value_unset (&v);
2153  return retval;
2154 }
2155 
2156 void
2157 xaccSplitVoid(Split *split)
2158 {
2159  gnc_numeric zero = gnc_numeric_zero(), num;
2160  GValue v = G_VALUE_INIT;
2161 
2162  g_value_init (&v, GNC_TYPE_NUMERIC);
2163  num = xaccSplitGetAmount(split);
2164  g_value_set_boxed (&v, &num);
2165  qof_instance_set_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
2166  g_value_reset (&v);
2167  num = xaccSplitGetValue(split);
2168  g_value_set_boxed (&v, &num);
2169  qof_instance_set_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
2170 
2171  /* Marking dirty handled by SetAmount etc. */
2172  xaccSplitSetAmount (split, zero);
2173  xaccSplitSetValue (split, zero);
2174  xaccSplitSetReconcile(split, VREC);
2175  g_value_unset (&v);
2176 }
2177 
2178 void
2179 xaccSplitUnvoid(Split *split)
2180 {
2183  xaccSplitSetReconcile(split, NREC);
2184  qof_instance_set_kvp (QOF_INSTANCE (split), NULL, 1, void_former_amt_str);
2185  qof_instance_set_kvp (QOF_INSTANCE (split), NULL, 1, void_former_val_str);
2186  qof_instance_set_dirty (QOF_INSTANCE (split));
2187 }
2188 
2189 /********************************************************************\
2190 \********************************************************************/
2191 /* QofObject function implementation */
2192 
2193 /* Hook into the QofObject registry */
2194 
2195 #ifdef _MSC_VER
2196 /* MSVC compiler doesn't have C99 "designated initializers"
2197  * so we wrap them in a macro that is empty on MSVC. */
2198 # define DI(x) /* */
2199 #else
2200 # define DI(x) x
2201 #endif
2202 static QofObject split_object_def =
2203 {
2204  DI(.interface_version = ) QOF_OBJECT_VERSION,
2205  DI(.e_type = ) GNC_ID_SPLIT,
2206  DI(.type_label = ) "Split",
2207  DI(.create = ) (gpointer)xaccMallocSplit,
2208  DI(.book_begin = ) NULL,
2209  DI(.book_end = ) NULL,
2210  DI(.is_dirty = ) qof_collection_is_dirty,
2211  DI(.mark_clean = ) qof_collection_mark_clean,
2212  DI(.foreach = ) qof_collection_foreach,
2213  DI(.printable = ) (const char * (*)(gpointer)) xaccSplitGetMemo,
2214  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
2215 };
2216 
2217 static gpointer
2218 split_account_guid_getter (gpointer obj, const QofParam *p)
2219 {
2220  Split *s = obj;
2221  Account *acc;
2222 
2223  if (!s) return NULL;
2224  acc = xaccSplitGetAccount (s);
2225  if (!acc) return NULL;
2226  return ((gpointer)xaccAccountGetGUID (acc));
2227 }
2228 
2229 static double /* internal use only */
2230 DxaccSplitGetShareAmount (const Split * split)
2231 {
2232  return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
2233 }
2234 
2235 static gpointer
2236 no_op (gpointer obj, const QofParam *p)
2237 {
2238  return obj;
2239 }
2240 
2241 static void
2242 qofSplitSetParentTrans(Split *s, QofInstance *ent)
2243 {
2244  Transaction *trans = (Transaction*)ent;
2245 
2246  g_return_if_fail(trans);
2247  xaccSplitSetParent(s, trans);
2248 }
2249 
2250 static void
2251 qofSplitSetAccount(Split *s, QofInstance *ent)
2252 {
2253  Account *acc = (Account*)ent;
2254 
2255  g_return_if_fail(acc);
2256  xaccSplitSetAccount(s, acc);
2257 }
2258 
2259 gboolean xaccSplitRegister (void)
2260 {
2261  static const QofParam params[] =
2262  {
2263  {
2264  SPLIT_DATE_RECONCILED, QOF_TYPE_DATE,
2267  },
2268 
2269  /* d-* are deprecated query params, should not be used in new
2270  * queries, should be removed from old queries. */
2271  {
2272  "d-share-amount", QOF_TYPE_DOUBLE,
2273  (QofAccessFunc)DxaccSplitGetShareAmount, NULL
2274  },
2275  {
2276  "d-share-int64", QOF_TYPE_INT64,
2278  },
2279  {
2280  SPLIT_BALANCE, QOF_TYPE_NUMERIC,
2282  },
2283  {
2284  SPLIT_CLEARED_BALANCE, QOF_TYPE_NUMERIC,
2286  },
2287  {
2288  SPLIT_RECONCILED_BALANCE, QOF_TYPE_NUMERIC,
2290  },
2291  {
2292  SPLIT_MEMO, QOF_TYPE_STRING,
2293  (QofAccessFunc)xaccSplitGetMemo, (QofSetterFunc)qofSplitSetMemo
2294  },
2295  {
2296  SPLIT_ACTION, QOF_TYPE_STRING,
2297  (QofAccessFunc)xaccSplitGetAction, (QofSetterFunc)qofSplitSetAction
2298  },
2299  {
2300  SPLIT_RECONCILE, QOF_TYPE_CHAR,
2302  (QofSetterFunc)qofSplitSetReconcile
2303  },
2304  {
2305  SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
2306  (QofAccessFunc)xaccSplitGetAmount, (QofSetterFunc)qofSplitSetAmount
2307  },
2308  {
2309  SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
2311  (QofSetterFunc)qofSplitSetSharePrice
2312  },
2313  {
2314  SPLIT_VALUE, QOF_TYPE_DEBCRED,
2315  (QofAccessFunc)xaccSplitGetValue, (QofSetterFunc)qofSplitSetValue
2316  },
2317  { SPLIT_TYPE, QOF_TYPE_STRING, (QofAccessFunc)xaccSplitGetType, NULL },
2318  {
2319  SPLIT_VOIDED_AMOUNT, QOF_TYPE_NUMERIC,
2321  },
2322  {
2323  SPLIT_VOIDED_VALUE, QOF_TYPE_NUMERIC,
2325  },
2326  { SPLIT_LOT, GNC_ID_LOT, (QofAccessFunc)xaccSplitGetLot, NULL },
2327  {
2328  SPLIT_TRANS, GNC_ID_TRANS,
2330  (QofSetterFunc)qofSplitSetParentTrans
2331  },
2332  {
2333  SPLIT_ACCOUNT, GNC_ID_ACCOUNT,
2334  (QofAccessFunc)xaccSplitGetAccount, (QofSetterFunc)qofSplitSetAccount
2335  },
2336  { SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, NULL },
2337  /* these are no-ops to register the parameter names (for sorting) but
2338  they return an allocated object which getters cannot do. */
2339  { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, NULL },
2340  { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, NULL },
2341  { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, NULL },
2342  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, NULL },
2343  {
2344  QOF_PARAM_GUID, QOF_TYPE_GUID,
2346  },
2347  { NULL },
2348  };
2349 
2350  qof_class_register (GNC_ID_SPLIT, (QofSortFunc)xaccSplitOrder, params);
2351  qof_class_register (SPLIT_ACCT_FULLNAME,
2353  qof_class_register (SPLIT_CORR_ACCT_NAME,
2355  NULL);
2356  qof_class_register (SPLIT_CORR_ACCT_CODE,
2358 
2359  return qof_object_register (&split_object_def);
2360 }
2361 
2363 _utest_split_fill_functions (void)
2364 {
2365  SplitTestFunctions *func = g_new (SplitTestFunctions, 1);
2366 
2367  func->xaccSplitEqualCheckBal = xaccSplitEqualCheckBal;
2368  func->get_currency_denom = get_currency_denom;
2369  func->get_commodity_denom = get_commodity_denom;
2370  func->get_corr_account_split = get_corr_account_split;
2371  return func;
2372 }
2373 
2374 /************************ END OF ************************************\
2375 \************************* FILE *************************************/
void xaccSplitSetValue(Split *s, gnc_numeric amt)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: Split.c:1270
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
gnc_numeric xaccSplitGetClearedBalance(const Split *s)
The cleared-balance is the currency-denominated balance of all transactions that have been marked as ...
Definition: Split.c:1311
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition: Split.c:1504
void xaccSplitAddPeerSplit(Split *split, const Split *other_split, time64 timestamp)
Add a peer split to this split&#39;s lot-split list.
Definition: Split.c:2020
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
void xaccSplitSetBaseValue(Split *s, gnc_numeric value, const gnc_commodity *base_currency)
Depending on the base_currency, set either the value or the amount of this split or both: If the base...
Definition: Split.c:1323
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition: Split.c:1751
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
void xaccSplitMakeStockSplit(Split *s)
Mark a split to be of type stock split - after this, you shouldn&#39;t modify the value anymore...
Definition: Split.c:2002
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void qof_instance_set_kvp(QofInstance *, GValue const *value, unsigned count,...)
Sets a KVP slot to a value from a GValue.
int xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
Compare two splits by code of account.
Definition: Split.c:1677
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
#define GNC_COMMODITY_MAX_FRACTION
Max fraction is 10^9 because 10^10 would require changing it to an int64_t.
#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 qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:257
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:215
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
gnc_numeric xaccSplitGetReconciledBalance(const Split *s)
Returns the reconciled-balance of this split.
Definition: Split.c:1317
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
const char * xaccAccountGetCode(const Account *acc)
Get the account&#39;s accounting code.
Definition: Account.cpp:3356
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition: guid.cpp:121
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:2567
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 qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the &#39;Num&#39; field, FALSE if it uses transaction nu...
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.
Definition: Split.c:1912
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
void gnc_lot_add_split(GNCLot *lot, Split *split)
The gnc_lot_add_split() routine adds a split to this lot.
Definition: gnc-lot.c:622
gboolean gnc_account_remove_split(Account *acc, Split *s)
Remove the given split from an account.
Definition: Account.cpp:1979
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Definition: Split.c:1784
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2143
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition: Split.c:1835
API for Transactions and Splits (journal entries)
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
void xaccSplitRemovePeerSplit(Split *split, const Split *other_split)
Remove a peer split from this split&#39;s lot-split list.
Definition: Split.c:2057
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:222
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
gboolean xaccTransIsBalanced(const Transaction *trans)
Returns true if the transaction is balanced according to the rules currently in effect.
Definition: Transaction.c:1142
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:64
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
int xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
Compare two splits by full name of the other account.
Definition: Split.c:1691
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
QofBook * xaccSplitGetBook(const Split *split)
Returns the book of this split, i.e.
Definition: Split.c:1969
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:1930
#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
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:109
Split * xaccSplitGetCapGainsSplit(const Split *split)
The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split...
Definition: cap-gains.c:482
void gnc_lot_set_closed_unknown(GNCLot *lot)
Reset closed flag so that it will be recalculated.
Definition: gnc-lot.c:425
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
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
Retrieves the contents of a KVP slot into a provided GValue.
int xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
Compare two splits by full name of account.
Definition: Split.c:1656
#define VREC
split is void
Definition: Split.h:75
Account used to record multiple commodity transactions.
Definition: Account.h:158
gboolean xaccSplitEqual(const Split *sa, const Split *sb, gboolean check_guids, gboolean check_balances, gboolean check_txn_splits)
Equality.
Definition: Split.c:769
gboolean xaccSplitHasPeers(const Split *split)
Does this split have peers?
Definition: Split.c:2038
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2396
#define xaccAccountGetGUID(X)
Definition: Account.h:248
double gnc_numeric_to_double(gnc_numeric in)
Convert numeric to floating-point value.
convert single-entry accounts to clean double-entry
void xaccSplitMergePeerSplits(Split *split, const Split *other_split)
Merge the other_split&#39;s peer splits into split&#39;s peers.
Definition: Split.c:2074
gnc_numeric xaccSplitVoidFormerAmount(const Split *split)
Returns the original pre-void amount of a split.
Definition: Split.c:2127
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.c:1072
guint32 qof_instance_get_idata(gconstpointer inst)
get the instance tag number used for kvp management in sql backends.
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: Split.c:1234
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3308
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_guids, gboolean check_splits, gboolean check_balances, gboolean assume_ordered)
Equality.
Definition: Transaction.c:874
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 xaccSplitVoidFormerValue(const Split *split)
Returns the original pre-void value of a split.
Definition: Split.c:2142
#define YREC
The Split has been reconciled.
Definition: Split.h:72
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
const char * gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
Returns a string representation of the given GNCNumericErrorCode.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition: Split.c:1732
#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
int xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
Compare two splits by code of the other account.
Definition: Split.c:1712
void xaccSplitSetSharePriceAndAmount(Split *s, gnc_numeric price, gnc_numeric amt)
The xaccSplitSetSharePriceAndAmount() method will simultaneously update the share price and the numbe...
Definition: Split.c:1168
void qof_instance_copy_book(gpointer ptr1, gconstpointer ptr2)
Copy the book from one QofInstances to another.
gnc_numeric xaccSplitGetNoclosingBalance(const Split *s)
The noclosing-balance is the currency-denominated balance of all transactions except &#39;closing&#39; transa...
Definition: Split.c:1305
#define SPLIT_ACCOUNT_GUID
for guid_match_all
Definition: Split.h:546
void xaccAccountRecomputeBalance(Account *acc)
The following recompute the partial balances (stored with the transaction) and the total balance...
Definition: Account.cpp:2281
gboolean xaccSplitIsPeerSplit(const Split *split, const Split *other_split)
Report if a split is a peer of this one.
Definition: Split.c:2044
char * xaccSplitGetCorrAccountFullName(const Split *sa)
These functions take a split, get the corresponding split on the "other side" of the transaction...
Definition: Split.c:1623
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
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:177
#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 xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
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
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
Definition: Split.c:1931
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
Definition: Transaction.c:2303
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and ...
All type declarations for the whole Gnucash engine.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
#define CREC
The Split has been cleared.
Definition: Split.h:71
gboolean qof_instance_books_equal(gconstpointer ptr1, gconstpointer ptr2)
See if two QofInstances share the same book.
gnc_numeric xaccSplitGetBaseValue(const Split *s, const gnc_commodity *base_currency)
Depending on the base_currency, return either the value or the amount of this split: If the base_curr...
Definition: Split.c:1378
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: Split.c:534
const char * xaccSplitGetCorrAccountName(const Split *sa)
document me
Definition: Split.c:1606
Encapsulate all the information about a dataset.
gboolean gnc_account_insert_split(Account *acc, Split *s)
Insert the given split from an account.
Definition: Account.cpp:1943
void xaccSplitSetLot(Split *split, GNCLot *lot)
Assigns the split to a specific Lot.
Definition: Split.c:1891
API for the transaction logger.
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
Retrieve the &#39;print&#39; name for the specified commodity.
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64. ...
Definition: Split.c:1810
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition: Split.c:1824
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: Split.c:1925
Account * xaccSplitGetAccount(const Split *s)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: Split.c:936
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1366
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1038
This is the private header for the account structure.
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
const char * xaccSplitGetCorrAccountCode(const Split *sa)
document me
Definition: Split.c:1639
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
Definition: Split.c:2097
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
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:1894
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: Split.c:1900
const char * xaccSplitGetAction(const Split *split)
Returns the action string.
Definition: Split.c:1906
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:530
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.c:392
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:317
const char * xaccSplitGetType(const Split *s)
The xaccIsPeerSplit() is a convenience routine that returns TRUE (a non-zero value) if the two splits...
Definition: Split.c:1975
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3301
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
#define GNC_EVENT_ITEM_ADDED
These events are used when a split is added to an account.
Definition: gnc-event.h:45
No error.
Definition: gnc-numeric.h:224
#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
Utilities to Automatically Compute Capital Gains/Losses.
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.
Commodity handling public routines.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
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
#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: Split.c:1919