GnuCash  5.6-150-g038405b370+
Split.cpp
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 "qofinstance.h"
28 #include <config.h>
29 
30 #include <platform.h>
31 #if PLATFORM(WINDOWS)
32 #include <windows.h>
33 #endif
34 
35 #include <glib.h>
36 #include <glib/gi18n.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42 #include <time.h>
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46 
47 #include "qof.h"
48 #include "qofbook.h"
49 #include "Split.h"
50 #include "AccountP.hpp"
51 #include "Account.hpp"
52 #include "Scrub.h"
53 #include "TransactionP.hpp"
54 #include "TransLog.h"
55 #include "cap-gains.h"
56 #include "gnc-commodity.h"
57 #include "gnc-engine.h"
58 #include "gnc-lot.h"
59 #include "gnc-event.h"
60 #include "qofinstance-p.h"
61 
62 const char *void_former_amt_str = "void-former-amount";
63 const char *void_former_val_str = "void-former-value";
64 
65 /* This static indicates the debugging module that this .o belongs to. */
66 static QofLogModule log_module = GNC_MOD_ENGINE;
67 
68 /* KVP key values used for SX info stored Split's slots. */
69 #define GNC_SX_ID "sched-xaction"
70 #define GNC_SX_ACCOUNT "account"
71 #define GNC_SX_CREDIT_FORMULA "credit-formula"
72 #define GNC_SX_DEBIT_FORMULA "debit-formula"
73 #define GNC_SX_CREDIT_NUMERIC "credit-numeric"
74 #define GNC_SX_DEBIT_NUMERIC "debit-numeric"
75 #define GNC_SX_SHARES "shares"
76 
77 enum
78 {
79  PROP_0,
80  PROP_TX, /* Table */
81  PROP_ACCOUNT, /* Table */
82  PROP_MEMO, /* Table */
83  PROP_ACTION, /* Table */
84 // PROP_RECONCILE_STATE, /* Table */
85  PROP_RECONCILE_DATE, /* Table */
86  PROP_VALUE, /* Table, in 2 fields */
87  PROP_SX_ACCOUNT, /* KVP */
88  PROP_SX_CREDIT_FORMULA, /* KVP */
89  PROP_SX_CREDIT_NUMERIC, /* KVP */
90  PROP_SX_DEBIT_FORMULA, /* KVP */
91  PROP_SX_DEBIT_NUMERIC, /* KVP */
92  PROP_SX_SHARES, /* KVP */
93  PROP_LOT, /* KVP */
94  PROP_ONLINE_ACCOUNT, /* KVP */
95  PROP_GAINS_SPLIT, /* KVP */
96  PROP_GAINS_SOURCE, /* KVP */
97  PROP_RUNTIME_0,
98  PROP_AMOUNT, /* Runtime */
99 
100 };
101 
102 static const char * split_type_normal = "normal";
103 static const char * split_type_stock_split = "stock-split";
104 static const char * split_online_id = "online_id";
105 
106 /* GObject Initialization */
107 G_DEFINE_TYPE(Split, gnc_split, QOF_TYPE_INSTANCE)
108 
109 static void
110 gnc_split_init(Split* split)
111 {
112  /* fill in some sane defaults */
113  split->acc = nullptr;
114  split->orig_acc = nullptr;
115  split->parent = nullptr;
116  split->lot = nullptr;
117 
118  split->action = CACHE_INSERT("");
119  split->memo = CACHE_INSERT("");
120  split->reconciled = NREC;
121  split->amount = gnc_numeric_zero();
122  split->value = gnc_numeric_zero();
123 
124  split->date_reconciled = 0;
125 
126  split->balance = gnc_numeric_zero();
127  split->cleared_balance = gnc_numeric_zero();
128  split->reconciled_balance = gnc_numeric_zero();
129  split->noclosing_balance = gnc_numeric_zero();
130 
131  split->gains = GAINS_STATUS_UNKNOWN;
132  split->gains_split = nullptr;
133 }
134 
135 static void
136 gnc_split_dispose(GObject *splitp)
137 {
138  G_OBJECT_CLASS(gnc_split_parent_class)->dispose(splitp);
139 }
140 
141 static void
142 gnc_split_finalize(GObject* splitp)
143 {
144  G_OBJECT_CLASS(gnc_split_parent_class)->finalize(splitp);
145 }
146 /* Note that g_value_set_object() refs the object, as does
147  * g_object_get(). But g_object_get() only unrefs once when it disgorges
148  * the object, leaving an unbalanced ref, which leaks. So instead of
149  * using g_value_set_object(), use g_value_take_object() which doesn't
150  * ref the object when used in get_property().
151  */
152 static void
153 gnc_split_get_property(GObject *object,
154  guint prop_id,
155  GValue *value,
156  GParamSpec *pspec)
157 {
158  Split *split;
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  Time64 *t;
233  g_return_if_fail(GNC_IS_SPLIT(object));
234 
235  split = GNC_SPLIT(object);
236  if (prop_id < PROP_RUNTIME_0 && split->parent != nullptr)
237  g_assert (qof_instance_get_editlevel(split->parent));
238 
239  switch (prop_id)
240  {
241  case PROP_ACTION:
242  xaccSplitSetAction(split, g_value_get_string(value));
243  break;
244  case PROP_MEMO:
245  xaccSplitSetMemo(split, g_value_get_string(value));
246  break;
247  case PROP_VALUE:
248  number = static_cast<gnc_numeric*>(g_value_get_boxed(value));
249  xaccSplitSetValue(split, *number);
250  break;
251  case PROP_AMOUNT:
252  number = static_cast<gnc_numeric*>(g_value_get_boxed(value));
253  xaccSplitSetAmount(split, *number);
254  break;
255  case PROP_RECONCILE_DATE:
256  t = static_cast<Time64*>(g_value_get_boxed(value));
257  xaccSplitSetDateReconciledSecs(split, t->t);
258  break;
259  case PROP_TX:
260  xaccSplitSetParent(split, GNC_TRANSACTION(g_value_get_object(value)));
261  break;
262  case PROP_ACCOUNT:
263  xaccSplitSetAccount(split, GNC_ACCOUNT(g_value_get_object(value)));
264  break;
265  case PROP_LOT:
266  xaccSplitSetLot(split, GNC_LOT(g_value_get_object(value)));
267  break;
268  case PROP_SX_CREDIT_FORMULA:
269  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
270  break;
271  case PROP_SX_CREDIT_NUMERIC:
272  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
273  break;
274  case PROP_SX_DEBIT_FORMULA:
275  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
276  break;
277  case PROP_SX_DEBIT_NUMERIC:
278  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
279  break;
280  case PROP_SX_ACCOUNT:
281  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
282  break;
283  case PROP_SX_SHARES:
284  qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
285  break;
286  case PROP_ONLINE_ACCOUNT:
287  qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "online_id");
288  break;
289  case PROP_GAINS_SPLIT:
290  qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
291  break;
292  case PROP_GAINS_SOURCE:
293  qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
294  break;
295  default:
296  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
297  break;
298  }
299 }
300 
301 static void
302 gnc_split_class_init(SplitClass* klass)
303 {
304  GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
305 
306  gobject_class->dispose = gnc_split_dispose;
307  gobject_class->finalize = gnc_split_finalize;
308  gobject_class->set_property = gnc_split_set_property;
309  gobject_class->get_property = gnc_split_get_property;
310 
311  g_object_class_install_property
312  (gobject_class,
313  PROP_ACTION,
314  g_param_spec_string("action",
315  "Action",
316  "The action is an arbitrary string assigned "
317  "by the user. It is intended to be a short "
318  "string that contains extra information about "
319  "this split.",
320  nullptr,
321  G_PARAM_READWRITE));
322 
323  g_object_class_install_property
324  (gobject_class,
325  PROP_MEMO,
326  g_param_spec_string("memo",
327  "Memo",
328  "The action is an arbitrary string assigned "
329  "by the user. It is intended to be a short "
330  "string that describes the purpose of "
331  "this split.",
332  nullptr,
333  G_PARAM_READWRITE));
334 
335  g_object_class_install_property
336  (gobject_class,
337  PROP_VALUE,
338  g_param_spec_boxed("value",
339  "Split Value",
340  "The value for this split in the common currency. "
341  "The value and the amount provide enough information to "
342  "calculate a conversion rate.",
343  GNC_TYPE_NUMERIC,
344  G_PARAM_READWRITE));
345 
346  g_object_class_install_property
347  (gobject_class,
348  PROP_AMOUNT,
349  g_param_spec_boxed("amount",
350  "Split Amount",
351  "The value for this split in the currency of its account. "
352  "The value and the amount provide enough information to "
353  "calculate a conversion rate.",
354  GNC_TYPE_NUMERIC,
355  G_PARAM_READWRITE));
356 
357  g_object_class_install_property
358  (gobject_class,
359  PROP_RECONCILE_DATE,
360  g_param_spec_boxed("reconcile-date",
361  "Reconcile Date",
362  "The date this split was reconciled.",
363  GNC_TYPE_TIME64,
364  G_PARAM_READWRITE));
365 
366  g_object_class_install_property
367  (gobject_class,
368  PROP_TX,
369  g_param_spec_object ("transaction",
370  "Transaction",
371  "The transaction that this split belongs to.",
372  GNC_TYPE_TRANSACTION,
373  G_PARAM_READWRITE));
374 
375  g_object_class_install_property
376  (gobject_class,
377  PROP_ACCOUNT,
378  g_param_spec_object ("account",
379  "Account",
380  "The account that this split belongs to.",
381  GNC_TYPE_ACCOUNT,
382  G_PARAM_READWRITE));
383 
384  g_object_class_install_property
385  (gobject_class,
386  PROP_LOT,
387  g_param_spec_object ("lot",
388  "Lot",
389  "The lot that this split belongs to.",
390  GNC_TYPE_LOT,
391  G_PARAM_READWRITE));
392 
393  g_object_class_install_property
394  (gobject_class,
395  PROP_SX_DEBIT_FORMULA,
396  g_param_spec_string("sx-debit-formula",
397  "Schedule Transaction Debit Formula",
398  "The formula used to calculate the actual debit "
399  "amount when a real split is generated from this "
400  "SX split.",
401  nullptr,
402  G_PARAM_READWRITE));
403 
404  g_object_class_install_property
405  (gobject_class,
406  PROP_SX_DEBIT_NUMERIC,
407  g_param_spec_boxed("sx-debit-numeric",
408  "Scheduled Transaction Debit Numeric",
409  "Numeric value to plug into the Debit Formula when a "
410  "real split is generated from this SX split.",
411  GNC_TYPE_NUMERIC,
412  G_PARAM_READWRITE));
413 
414  g_object_class_install_property
415  (gobject_class,
416  PROP_SX_CREDIT_FORMULA,
417  g_param_spec_string("sx-credit-formula",
418  "Schedule Transaction Credit Formula",
419  "The formula used to calculate the actual credit "
420  "amount when a real split is generated from this "
421  "SX split.",
422  nullptr,
423  G_PARAM_READWRITE));
424 
425  g_object_class_install_property
426  (gobject_class,
427  PROP_SX_CREDIT_NUMERIC,
428  g_param_spec_boxed("sx-credit-numeric",
429  "Scheduled Transaction Credit Numeric",
430  "Numeric value to plug into the Credit Formula when a "
431  "real split is generated from this SX split.",
432  GNC_TYPE_NUMERIC,
433  G_PARAM_READWRITE));
434 /* FIXME: PROP_SX_SHARES should be stored as a gnc_numeric, but the function
435  * which uses it, gnc_template_register_save_shares_cell, stores a
436  * phony string. This is maintained until backwards compatibility can
437  * be established.
438  */
439  g_object_class_install_property
440  (gobject_class,
441  PROP_SX_SHARES,
442  g_param_spec_string("sx-shares",
443  "Scheduled Transaction Shares",
444  "Numeric value of shares to insert in a new split when "
445  "it's generated from this SX split.",
446  nullptr,
447  G_PARAM_READWRITE));
448 
449  g_object_class_install_property
450  (gobject_class,
451  PROP_SX_ACCOUNT,
452  g_param_spec_boxed("sx-account",
453  "Scheduled Transaction Account",
454  "The target account for a scheduled transaction split.",
455  GNC_TYPE_GUID,
456  G_PARAM_READWRITE));
457 
458  g_object_class_install_property
459  (gobject_class,
460  PROP_ONLINE_ACCOUNT,
461  g_param_spec_string ("online-id",
462  "Online Account ID",
463  "The online account which corresponds to this "
464  "account for OFX/HCBI import",
465  nullptr,
466  G_PARAM_READWRITE));
467 
468  g_object_class_install_property
469  (gobject_class,
470  PROP_GAINS_SPLIT,
471  g_param_spec_boxed ("gains-split",
472  "Gains Split",
473  "The capital gains split associated with this "
474  "split when this split represents the proceeds "
475  "from the sale of a commodity inside a Lot.",
476  GNC_TYPE_GUID,
477  G_PARAM_READWRITE));
478 
479  g_object_class_install_property
480  (gobject_class,
481  PROP_GAINS_SOURCE,
482  g_param_spec_boxed ("gains-source",
483  "Gains Source",
484  "The source split for which this split this is "
485  "the gains split. ",
486  GNC_TYPE_GUID,
487  G_PARAM_READWRITE));
488 }
489 
490 /********************************************************************\
491  * xaccInitSplit
492  * Initialize a Split structure
493 \********************************************************************/
494 
495 static void
496 xaccInitSplit(Split * split, QofBook *book)
497 {
498  qof_instance_init_data(&split->inst, GNC_ID_SPLIT, book);
499 }
500 
501 void
502 xaccSplitReinit(Split * split)
503 {
504  /* fill in some sane defaults */
505  split->acc = nullptr;
506  split->orig_acc = nullptr;
507  split->parent = nullptr;
508  split->lot = nullptr;
509 
510  CACHE_REPLACE(split->action, "");
511  CACHE_REPLACE(split->memo, "");
512  split->reconciled = NREC;
513  split->amount = gnc_numeric_zero();
514  split->value = gnc_numeric_zero();
515 
516  split->date_reconciled = 0;
517 
518  split->balance = gnc_numeric_zero();
519  split->cleared_balance = gnc_numeric_zero();
520  split->reconciled_balance = gnc_numeric_zero();
521  split->noclosing_balance = gnc_numeric_zero();
522 
523  qof_instance_set_idata(split, 0);
524 
525  split->gains = GAINS_STATUS_UNKNOWN;
526  split->gains_split = nullptr;
527 }
528 
529 /********************************************************************\
530 \********************************************************************/
531 
532 Split *
534 {
535  Split *split;
536  g_return_val_if_fail (book, nullptr);
537 
538  split = GNC_SPLIT(g_object_new (GNC_TYPE_SPLIT, nullptr));
539  xaccInitSplit (split, book);
540 
541  return split;
542 }
543 
544 /********************************************************************\
545 \********************************************************************/
546 /* This routine is not exposed externally, since it does weird things,
547  * like not really setting up the parent account correctly, and ditto
548  * the parent transaction. This routine is prone to programmer error
549  * if not used correctly. It is used only by the edit-rollback code.
550  * Don't get duped!
551  */
552 
553 Split *
554 xaccDupeSplit (const Split *s)
555 {
556  Split *split = GNC_SPLIT(g_object_new (GNC_TYPE_SPLIT, nullptr));
557 
558  /* Trash the entity table. We don't want to mistake the cloned
559  * splits as something official. If we ever use this split, we'll
560  * have to fix this up.
561  */
562  split->inst.e_type = nullptr;
563  qof_instance_copy_guid(split, s);
564  qof_instance_copy_book(split, s);
565 
566  split->parent = s->parent;
567  split->acc = s->acc;
568  split->orig_acc = s->orig_acc;
569  split->lot = s->lot;
570 
571  CACHE_REPLACE(split->memo, s->memo);
572  CACHE_REPLACE(split->action, s->action);
573 
574  qof_instance_copy_kvp (QOF_INSTANCE (split), QOF_INSTANCE (s));
575 
576  split->reconciled = s->reconciled;
577  split->date_reconciled = s->date_reconciled;
578 
579  split->value = s->value;
580  split->amount = s->amount;
581 
582  /* no need to futz with the balances; these get wiped each time ...
583  * split->balance = s->balance;
584  * split->cleared_balance = s->cleared_balance;
585  * split->reconciled_balance = s->reconciled_balance;
586  */
587 
588  return split;
589 }
590 
591 Split *
592 xaccSplitCloneNoKvp (const Split *s)
593 {
594  Split *split = GNC_SPLIT(g_object_new (GNC_TYPE_SPLIT, nullptr));
595 
596  split->parent = nullptr;
597  split->memo = CACHE_INSERT(s->memo);
598  split->action = CACHE_INSERT(s->action);
599  split->reconciled = s->reconciled;
600  split->date_reconciled = s->date_reconciled;
601  split->value = s->value;
602  split->amount = s->amount;
603  split->balance = s->balance;
604  split->cleared_balance = s->cleared_balance;
605  split->reconciled_balance = s->reconciled_balance;
606  split->noclosing_balance = s->noclosing_balance;
607 
608  split->gains = GAINS_STATUS_UNKNOWN;
609  split->gains_split = nullptr;
610 
611  qof_instance_init_data(&split->inst, GNC_ID_SPLIT,
613  xaccAccountInsertSplit(s->acc, split);
614  if (s->lot)
615  {
616  /* CHECKME: Is this right? */
617  gnc_lot_add_split(s->lot, split);
618  }
619  return split;
620 }
621 
622 void
623 xaccSplitCopyKvp (const Split *from, Split *to)
624 {
625  qof_instance_copy_kvp (QOF_INSTANCE (to), QOF_INSTANCE (from));
626  /* But not the online-id */
627  qof_instance_set (QOF_INSTANCE (to), "online-id", nullptr, nullptr);
628 }
629 
630 /*################## Added for Reg2 #################*/
631 
632 /* This is really a helper for xaccTransCopyOnto. It doesn't reparent
633  the 'to' split to from's transaction, because xaccTransCopyOnto is
634  responsible for parenting the split to the correct transaction.
635  Also, from's parent transaction may not even be a valid
636  transaction, so this function may not modify anything about 'from'
637  or from's transaction.
638 */
639 void
640 xaccSplitCopyOnto(const Split *from_split, Split *to_split)
641 {
642  if (!from_split || !to_split) return;
643  xaccTransBeginEdit (to_split->parent);
644 
645  xaccSplitSetMemo(to_split, xaccSplitGetMemo(from_split));
646  xaccSplitSetAction(to_split, xaccSplitGetAction(from_split));
647  xaccSplitSetAmount(to_split, xaccSplitGetAmount(from_split));
648  xaccSplitSetValue(to_split, xaccSplitGetValue(from_split));
649  /* Setting the account is okay here because, even though the from
650  split might not really belong to the account it claims to,
651  setting the account won't cause any event involving from. */
652  xaccSplitSetAccount(to_split, xaccSplitGetAccount(from_split));
653  /* N.B. Don't set parent. */
654 
655  qof_instance_set_dirty(QOF_INSTANCE(to_split));
656  xaccTransCommitEdit(to_split->parent);
657 }
658 
659 /*################## Added for Reg2 #################*/
660 
661 
662 #ifdef DUMP_FUNCTIONS
663 void
664 xaccSplitDump (const Split *split, const char *tag)
665 {
666  char datebuff[MAX_DATE_LENGTH + 1];
667  memset (datebuff, 0, sizeof(datebuff));
668  qof_print_date_buff (datebuff, MAX_DATE_LENGTH, split->date_reconciled);
669  printf(" %s Split %p", tag, split);
670  printf(" Book: %p\n", qof_instance_get_book(split));
671  printf(" Account: %p (%s)\n", split->acc,
672  split->acc ? xaccAccountGetName(split->acc) : "");
673  printf(" Commod: %s\n",
674  split->acc ?
676  : "");
677  printf(" Lot: %p\n", split->lot);
678  printf(" Parent: %p\n", split->parent);
679  printf(" Gains: %p\n", split->gains_split);
680  printf(" Memo: %s\n", split->memo ? split->memo : "(null)");
681  printf(" Action: %s\n", split->action ? split->action : "(null)");
682  printf(" KVP Data: %s\n", qof_instance_kvp_as_string (QOF_INSTANCE (split)));
683  printf(" Recncld: %c (date %s)\n", split->reconciled, datebuff);
684 
685  printf(" Value: %s\n", gnc_numeric_to_string(split->value));
686  printf(" Amount: %s\n", gnc_numeric_to_string(split->amount));
687  printf(" Balance: %s\n", gnc_numeric_to_string(split->balance));
688  printf(" CBalance: %s\n", gnc_numeric_to_string(split->cleared_balance));
689  printf(" RBalance: %s\n",
690  gnc_numeric_to_string(split->reconciled_balance));
691  printf(" NoClose: %s\n", gnc_numeric_to_string(split->noclosing_balance));
692  printf(" idata: %x\n", qof_instance_get_idata(split));
693 }
694 #endif
695 
696 /********************************************************************\
697 \********************************************************************/
698 static void
699 do_destroy (QofInstance *inst)
700 {
701  xaccFreeSplit (GNC_SPLIT (inst));
702 }
703 
704 void
705 xaccFreeSplit (Split *split)
706 {
707  if (!split) return;
708 
709  /* Debug double-free's */
710  if (((char *) 1) == split->memo)
711  {
712  PERR ("double-free %p", split);
713  return;
714  }
715  CACHE_REMOVE(split->memo);
716  CACHE_REMOVE(split->action);
717 
718  if (split->inst.e_type) /* Don't do this for dupe splits. */
719  {
720  /* gnc_lot_remove_split needs the account, so do it first. */
721  if (GNC_IS_LOT (split->lot) && !qof_instance_get_destroying (QOF_INSTANCE (split->lot)))
722  gnc_lot_remove_split (split->lot, split);
723  if (GNC_IS_ACCOUNT (split->acc)
724  && !qof_instance_get_destroying (QOF_INSTANCE (split->acc)))
725  {
726  gnc_account_remove_split (split->acc, split);
727  /* gnc_float_split_to_split generates a qof_event_gen via
728  * xaccAccountCommitEdit even though it doesn't touch the
729  * account. That causes QofQueryViews to notice the split
730  * even though it isn't added to the account. We need a
731  * countervailing event so that they'll notice it's not
732  * there any more.
733  */
734  qof_event_gen(&split->acc->inst, QOF_EVENT_MODIFY, nullptr);
735  }
736  /* We should do the same for split->parent but we might be getting
737  * called from xaccFreeTransaction and that would cause trouble.
738  */
739  }
740 
741  /* Just in case someone looks up freed memory ... */
742  split->memo = (char *) 1;
743  split->action = nullptr;
744  split->reconciled = NREC;
745  split->amount = gnc_numeric_zero();
746  split->value = gnc_numeric_zero();
747  split->parent = nullptr;
748  split->lot = nullptr;
749  split->acc = nullptr;
750  split->orig_acc = nullptr;
751 
752  split->date_reconciled = 0;
753  G_OBJECT_CLASS (QOF_INSTANCE_GET_CLASS (&split->inst))->dispose(G_OBJECT (split));
754 
755  if (split->gains_split)
756  {
757  Split *other = xaccSplitGetOtherSplit(split->gains_split);
758  split->gains_split->gains_split = nullptr;
759  if (other)
760  other->gains_split = nullptr;
761  }
762 
763  g_object_unref(split);
764 }
765 
766 void mark_split (Split *s)
767 {
768  if (s->acc)
769  {
770  g_object_set(s->acc, "sort-dirty", TRUE, "balance-dirty", TRUE, nullptr);
771  }
772 
773  /* set dirty flag on lot too. */
774  if (s->lot) gnc_lot_set_closed_unknown(s->lot);
775 }
776 
777 /*
778  * Helper routine for xaccSplitEqual.
779  */
780 static gboolean
781 xaccSplitEqualCheckBal (const char *tag, gnc_numeric a, gnc_numeric b)
782 {
783  char *str_a, *str_b;
784 
785  if (gnc_numeric_equal (a, b))
786  return TRUE;
787 
788  str_a = gnc_numeric_to_string (a);
789  str_b = gnc_numeric_to_string (b);
790 
791  PINFO ("%sbalances differ: %s vs %s", tag, str_a, str_b);
792 
793  g_free (str_a);
794  g_free (str_b);
795 
796  return FALSE;
797 }
798 
799 /********************************************************************
800  * xaccSplitEqual
801  ********************************************************************/
802 gboolean
803 xaccSplitEqual(const Split *sa, const Split *sb,
804  gboolean check_guids,
805  gboolean check_balances,
806  gboolean check_txn_splits)
807 {
808  gboolean same_book;
809 
810  if (!sa && !sb) return TRUE; /* Arguable. FALSE is better, methinks */
811 
812  if (!sa || !sb)
813  {
814  PINFO ("one is nullptr");
815  return FALSE;
816  }
817 
818  if (sa == sb) return TRUE;
819 
820  same_book = qof_instance_get_book(QOF_INSTANCE(sa)) == qof_instance_get_book(QOF_INSTANCE(sb));
821 
822  if (check_guids)
823  {
824  if (qof_instance_guid_compare(sa, sb) != 0)
825  {
826  PINFO ("GUIDs differ");
827  return FALSE;
828  }
829  }
830 
831  /* If the same book, since these strings are cached we can just use pointer equality */
832  if ((same_book && sa->memo != sb->memo) || (!same_book && g_strcmp0(sa->memo, sb->memo) != 0))
833  {
834  PINFO ("memos differ: (%p)%s vs (%p)%s",
835  sa->memo, sa->memo, sb->memo, sb->memo);
836  return FALSE;
837  }
838 
839  if ((same_book && sa->action != sb->action) || (!same_book && g_strcmp0(sa->action, sb->action) != 0))
840  {
841  PINFO ("actions differ: %s vs %s", sa->action, sb->action);
842  return FALSE;
843  }
844 
845  if (qof_instance_compare_kvp (QOF_INSTANCE (sa), QOF_INSTANCE (sb)) != 0)
846  {
847  char *frame_a;
848  char *frame_b;
849 
850  frame_a = qof_instance_kvp_as_string (QOF_INSTANCE (sa));
851  frame_b = qof_instance_kvp_as_string (QOF_INSTANCE (sb));
852 
853  PINFO ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
854 
855  g_free (frame_a);
856  g_free (frame_b);
857 
858  return FALSE;
859  }
860 
861  if (sa->reconciled != sb->reconciled)
862  {
863  PINFO ("reconcile flags differ: %c vs %c", sa->reconciled, sb->reconciled);
864  return FALSE;
865  }
866 
867  if (sa->date_reconciled != sb->date_reconciled)
868  {
869  PINFO ("reconciled date differs");
870  return FALSE;
871  }
872 
874  {
875  char *str_a;
876  char *str_b;
877 
880 
881  PINFO ("amounts differ: %s vs %s", str_a, str_b);
882 
883  g_free (str_a);
884  g_free (str_b);
885 
886  return FALSE;
887  }
888 
890  {
891  char *str_a;
892  char *str_b;
893 
896 
897  PINFO ("values differ: %s vs %s", str_a, str_b);
898 
899  g_free (str_a);
900  g_free (str_b);
901 
902  return FALSE;
903  }
904 
905  if (check_balances)
906  {
907  if (!xaccSplitEqualCheckBal ("", sa->balance, sb->balance))
908  return FALSE;
909  if (!xaccSplitEqualCheckBal ("cleared ", sa->cleared_balance,
910  sb->cleared_balance))
911  return FALSE;
912  if (!xaccSplitEqualCheckBal ("reconciled ", sa->reconciled_balance,
913  sb->reconciled_balance))
914  return FALSE;
915  if (!xaccSplitEqualCheckBal ("noclosing ", sa->noclosing_balance,
916  sb->noclosing_balance))
917  return FALSE;
918  }
919 
920  if (!xaccTransEqual(sa->parent, sb->parent, check_guids, check_txn_splits,
921  check_balances, FALSE))
922  {
923  PINFO ("transactions differ");
924  return FALSE;
925  }
926 
927  return TRUE;
928 }
929 
930 
931 
932 /********************************************************************
933  * Account funcs
934  ********************************************************************/
935 
936 Account *
937 xaccSplitGetAccount (const Split *s)
938 {
939  return s ? s->acc : nullptr;
940 }
941 
942 void
943 xaccSplitSetAccount (Split *s, Account *acc)
944 {
945  Transaction *trans;
946 
947  g_return_if_fail(s && acc);
948  g_return_if_fail(qof_instance_books_equal(acc, s));
949 
950  trans = s->parent;
951  if (trans)
952  xaccTransBeginEdit(trans);
953 
954  s->acc = acc;
955  qof_instance_set_dirty(QOF_INSTANCE(s));
956 
957  if (trans)
958  xaccTransCommitEdit(trans);
959 }
960 
961 static void commit_err (QofInstance *inst, QofBackendError errcode)
962 {
963  PERR("commit error: %d", errcode);
964  gnc_engine_signal_commit_error( errcode );
965 }
966 
967 /* An engine-private helper for completing xaccTransCommitEdit(). */
968 void
969 xaccSplitCommitEdit(Split *s)
970 {
971  Account *acc = nullptr;
972  Account *orig_acc = nullptr;
973 
974  g_return_if_fail(s);
975  if (!qof_instance_is_dirty(QOF_INSTANCE(s)))
976  return;
977 
978  orig_acc = s->orig_acc;
979 
980  if (GNC_IS_ACCOUNT(s->acc))
981  acc = s->acc;
982 
983  /* Remove from lot (but only if it hasn't been moved to
984  new lot already) */
985  if (s->lot && (gnc_lot_get_account(s->lot) != acc || qof_instance_get_destroying(s)))
986  gnc_lot_remove_split (s->lot, s);
987 
988  /* Possibly remove the split from the original account... */
989  if (orig_acc && (orig_acc != acc || qof_instance_get_destroying(s)))
990  {
991  if (!gnc_account_remove_split(orig_acc, s))
992  {
993  PERR("Account lost track of moved or deleted split.");
994  }
995  }
996 
997  /* ... and insert it into the new account if needed */
998  if (acc && (orig_acc != acc) && !qof_instance_get_destroying(s))
999  {
1000  if (gnc_account_insert_split(acc, s))
1001  {
1002  /* If the split's lot belonged to some other account, we
1003  leave it so. */
1004  if (s->lot && (nullptr == gnc_lot_get_account(s->lot)))
1005  xaccAccountInsertLot (acc, s->lot);
1006  }
1007  else
1008  {
1009  PERR("Account grabbed split prematurely.");
1010  }
1012  }
1013 
1014  if (s->parent != s->orig_parent)
1015  {
1016  //FIXME: find better event
1017  if (s->orig_parent)
1018  qof_event_gen(&s->orig_parent->inst, QOF_EVENT_MODIFY,
1019  nullptr);
1020  }
1021  if (s->lot)
1022  {
1023  /* A change of value/amnt affects gains display, etc. */
1024  qof_event_gen (QOF_INSTANCE(s->lot), QOF_EVENT_MODIFY, nullptr);
1025  }
1026 
1027  /* Important: we save off the original parent transaction and account
1028  so that when we commit, we can generate signals for both the
1029  original and new transactions, for the _next_ begin/commit cycle. */
1030  s->orig_acc = s->acc;
1031  s->orig_parent = s->parent;
1032  if (!qof_commit_edit_part2(QOF_INSTANCE(s), commit_err, nullptr, do_destroy))
1033  return;
1034 
1035  if (acc)
1036  {
1037  g_object_set(acc, "sort-dirty", TRUE, "balance-dirty", TRUE, nullptr);
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 nullptr. 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 nullptr;
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  GncGUID *guid = nullptr;
1095 
1096  if (GAINS_STATUS_UNKNOWN != split->gains) return;
1097 
1098  other = xaccSplitGetCapGainsSplit (split);
1099  if (other)
1100  {
1101  split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1102  split->gains_split = other;
1103  return;
1104  }
1105 
1106  if (auto v = qof_instance_get_path_kvp<GncGUID*> (QOF_INSTANCE (split), {"gains-source"}))
1107  guid = const_cast<GncGUID*>(*v);
1108 
1109  if (!guid)
1110  {
1111  // CHECKME: We leave split->gains_split alone. Is that correct?
1112  split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1113  }
1114  else
1115  {
1116  QofCollection *col;
1118  GNC_ID_SPLIT);
1119  split->gains = GAINS_STATUS_GAINS;
1120  other = (Split *) qof_collection_lookup_entity (col, guid);
1121  split->gains_split = other;
1122  }
1123 }
1124 
1125 /********************************************************************\
1126 \********************************************************************/
1127 
1128 static inline int
1129 get_currency_denom(const Split * s)
1130 {
1131  if (!(s && s->parent && s->parent->common_currency))
1132  {
1133  return GNC_DENOM_AUTO;
1134  }
1135  else
1136  {
1137  return gnc_commodity_get_fraction (s->parent->common_currency);
1138  }
1139 }
1140 
1141 static inline int
1142 get_commodity_denom(const Split * s)
1143 {
1144  if (!(s && s->acc))
1145  {
1146  return GNC_DENOM_AUTO;
1147  }
1148  else
1149  {
1150  return xaccAccountGetCommoditySCU(s->acc);
1151  }
1152 }
1153 
1154 /********************************************************************\
1155 \********************************************************************/
1156 
1157 void
1158 xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)
1159 {
1160  if (!s) return;
1161  ENTER (" ");
1162  xaccTransBeginEdit (s->parent);
1163 
1164  s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1166  s->value = gnc_numeric_mul(s->amount, price,
1167  get_currency_denom(s), GNC_HOW_RND_ROUND_HALF_UP);
1168 
1169  SET_GAINS_A_VDIRTY(s);
1170  mark_split (s);
1171  qof_instance_set_dirty(QOF_INSTANCE(s));
1172  xaccTransCommitEdit(s->parent);
1173  LEAVE ("");
1174 }
1175 
1176 static void
1177 qofSplitSetSharePrice (Split *split, gnc_numeric price)
1178 {
1179  g_return_if_fail(split);
1180  split->value = gnc_numeric_mul(xaccSplitGetAmount(split),
1181  price, get_currency_denom(split),
1183 }
1184 
1185 void
1186 xaccSplitSetSharePrice (Split *s, gnc_numeric price)
1187 {
1188  if (!s) return;
1189 
1190  if (gnc_numeric_zero_p (price))
1191  return;
1192 
1193  ENTER (" ");
1194  xaccTransBeginEdit (s->parent);
1195 
1196  s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
1197  price, get_currency_denom(s),
1199 
1200  SET_GAINS_VDIRTY(s);
1201  mark_split (s);
1202  qof_instance_set_dirty(QOF_INSTANCE(s));
1203  xaccTransCommitEdit(s->parent);
1204  LEAVE ("");
1205 }
1206 
1207 static void
1208 qofSplitSetAmount (Split *split, gnc_numeric amt)
1209 {
1210  g_return_if_fail(split);
1211  if (split->acc)
1212  {
1213  split->amount = gnc_numeric_convert(amt,
1214  get_commodity_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1215  }
1216  else
1217  {
1218  split->amount = amt;
1219  }
1220 }
1221 
1222 /* The amount of the split in the _account's_ commodity. */
1223 void
1224 xaccSplitSetAmount (Split *s, gnc_numeric amt)
1225 {
1226  if (!s) return;
1227  g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1228  ENTER ("(split=%p) old amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1229  " new amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1230  s->amount.num, s->amount.denom, amt.num, amt.denom);
1231 
1232  xaccTransBeginEdit (s->parent);
1233  if (s->acc)
1234  {
1235  s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1237  g_assert (gnc_numeric_check (s->amount) == GNC_ERROR_OK);
1238  }
1239  else
1240  s->amount = amt;
1241 
1242  SET_GAINS_ADIRTY(s);
1243  mark_split (s);
1244  qof_instance_set_dirty(QOF_INSTANCE(s));
1245  xaccTransCommitEdit(s->parent);
1246  LEAVE("");
1247 }
1248 
1249 static void
1250 qofSplitSetValue (Split *split, gnc_numeric amt)
1251 {
1252  g_return_if_fail(split);
1253  split->value = gnc_numeric_convert(amt,
1254  get_currency_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1255  g_assert(gnc_numeric_check (split->value) != GNC_ERROR_OK);
1256 }
1257 
1258 /* The value of the split in the _transaction's_ currency. */
1259 void
1260 xaccSplitSetValue (Split *s, gnc_numeric amt)
1261 {
1262  gnc_numeric new_val;
1263  if (!s) return;
1264 
1265  g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1266  ENTER ("(split=%p) old val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1267  " new val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1268  s->value.num, s->value.denom, amt.num, amt.denom);
1269 
1270  xaccTransBeginEdit (s->parent);
1271  new_val = gnc_numeric_convert(amt, get_currency_denom(s),
1273  if (gnc_numeric_check(new_val) == GNC_ERROR_OK &&
1274  !(gnc_numeric_zero_p (new_val) && !gnc_numeric_zero_p (amt)))
1275  {
1276  s->value = new_val;
1277  }
1278  else
1279  {
1280  PERR("numeric error %s in converting the split value's denominator with amount %s and denom %d",
1282  gnc_num_dbg_to_string (amt), get_currency_denom(s));
1283  }
1284 
1285  SET_GAINS_VDIRTY(s);
1286  mark_split (s);
1287  qof_instance_set_dirty(QOF_INSTANCE(s));
1288  xaccTransCommitEdit(s->parent);
1289  LEAVE ("");
1290 }
1291 
1292 /********************************************************************\
1293 \********************************************************************/
1294 
1295 gnc_numeric
1296 xaccSplitGetBalance (const Split *s)
1297 {
1298  return s ? s->balance : gnc_numeric_zero();
1299 }
1300 
1301 gnc_numeric
1303 {
1304  return s ? s->noclosing_balance : gnc_numeric_zero();
1305 }
1306 
1307 gnc_numeric
1309 {
1310  return s ? s->cleared_balance : gnc_numeric_zero();
1311 }
1312 
1313 gnc_numeric
1315 {
1316  return s ? s->reconciled_balance : gnc_numeric_zero();
1317 }
1318 
1319 void
1320 xaccSplitSetBaseValue (Split *s, gnc_numeric value,
1321  const gnc_commodity * base_currency)
1322 {
1323  const gnc_commodity *currency;
1324  const gnc_commodity *commodity;
1325 
1326  if (!s) return;
1327  xaccTransBeginEdit (s->parent);
1328 
1329  if (!s->acc)
1330  {
1331  PERR ("split must have a parent account");
1332  return;
1333  }
1334 
1335  currency = xaccTransGetCurrency (s->parent);
1336  commodity = xaccAccountGetCommodity (s->acc);
1337 
1338  /* If the base_currency is the transaction's commodity ('currency'),
1339  * set the value. If it's the account commodity, set the
1340  * amount. If both, set both. */
1341  if (gnc_commodity_equiv(currency, base_currency))
1342  {
1343  if (gnc_commodity_equiv(commodity, base_currency))
1344  {
1345  s->amount = gnc_numeric_convert(value,
1346  get_commodity_denom(s),
1348  }
1349  s->value = gnc_numeric_convert(value,
1350  get_currency_denom(s),
1352  }
1353  else if (gnc_commodity_equiv(commodity, base_currency))
1354  {
1355  s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
1357  }
1358  else
1359  {
1360  PERR ("inappropriate base currency %s "
1361  "given split currency=%s and commodity=%s\n",
1362  gnc_commodity_get_printname(base_currency),
1363  gnc_commodity_get_printname(currency),
1364  gnc_commodity_get_printname(commodity));
1365  return;
1366  }
1367 
1368  SET_GAINS_A_VDIRTY(s);
1369  mark_split (s);
1370  qof_instance_set_dirty(QOF_INSTANCE(s));
1371  xaccTransCommitEdit(s->parent);
1372 }
1373 
1374 gnc_numeric
1375 xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)
1376 {
1377  if (!s || !s->acc || !s->parent) return gnc_numeric_zero();
1378 
1379  /* be more precise -- the value depends on the currency we want it
1380  * expressed in. */
1381  if (gnc_commodity_equiv(xaccTransGetCurrency(s->parent), base_currency))
1382  return xaccSplitGetValue(s);
1383  if (gnc_commodity_equiv(xaccAccountGetCommodity(s->acc), base_currency))
1384  return xaccSplitGetAmount(s);
1385 
1386  PERR ("inappropriate base currency %s "
1387  "given split currency=%s and commodity=%s\n",
1388  gnc_commodity_get_printname(base_currency),
1391  return gnc_numeric_zero();
1392 }
1393 
1394 /********************************************************************\
1395 \********************************************************************/
1396 
1397 gnc_numeric
1398 xaccSplitConvertAmount (const Split *split, const Account * account)
1399 {
1400  gnc_commodity *acc_com, *to_commodity;
1401  Transaction *txn;
1402  gnc_numeric amount, value, convrate;
1403  Account * split_acc;
1404 
1405  amount = xaccSplitGetAmount (split);
1406 
1407  /* If this split is attached to this account, OR */
1408  split_acc = xaccSplitGetAccount (split);
1409  if (split_acc == account)
1410  return amount;
1411 
1412  /* If split->account->commodity == to_commodity, return the amount */
1413  acc_com = xaccAccountGetCommodity (split_acc);
1414  to_commodity = xaccAccountGetCommodity (account);
1415  if (acc_com && gnc_commodity_equal (acc_com, to_commodity))
1416  return amount;
1417 
1418  /* Ok, this split is not for the viewed account, and the commodity
1419  * does not match. So we need to do some conversion.
1420  *
1421  * First, we can cheat. If this transaction is balanced and has
1422  * exactly two splits, then we can implicitly determine the exchange
1423  * rate and just return the 'other' split amount.
1424  */
1425  txn = xaccSplitGetParent (split);
1426  if (txn && xaccTransIsBalanced (txn))
1427  {
1428  const Split *osplit = xaccSplitGetOtherSplit (split);
1429 
1430  if (osplit)
1431  {
1432  gnc_commodity* split_comm =
1434  if (!gnc_commodity_equal(to_commodity, split_comm))
1435  {
1436  gchar guidstr[GUID_ENCODING_LENGTH+1];
1437  guid_to_string_buff(xaccSplitGetGUID(osplit),guidstr);
1438  PERR("The split's (%s) amount can't be converted from %s into %s.",
1439  guidstr,
1440  gnc_commodity_get_mnemonic(split_comm),
1441  gnc_commodity_get_mnemonic(to_commodity)
1442  );
1443  return gnc_numeric_zero();
1444  }
1445  return gnc_numeric_neg (xaccSplitGetAmount (osplit));
1446  }
1447  }
1448 
1449  /* ... otherwise, we need to compute the amount from the conversion
1450  * rate into _this account_. So, find the split into this account,
1451  * compute the conversion rate (based on amount/value), and then multiply
1452  * this times the split value.
1453  */
1454  value = xaccSplitGetValue (split);
1455 
1456  if (gnc_numeric_zero_p (value))
1457  {
1458  return value;
1459  }
1460 
1461  convrate = xaccTransGetAccountConvRate(txn, account);
1462  return gnc_numeric_mul (value, convrate,
1463  gnc_commodity_get_fraction (to_commodity),
1465 }
1466 
1467 /********************************************************************\
1468 \********************************************************************/
1469 
1470 gboolean
1471 xaccSplitDestroy (Split *split)
1472 {
1473  Account *acc;
1474  Transaction *trans;
1475  GncEventData ed;
1476 
1477  if (!split) return TRUE;
1478 
1479  acc = split->acc;
1480  trans = split->parent;
1481  if (acc && !qof_instance_get_destroying(acc)
1482  && !qof_instance_get_destroying(trans)
1483  && xaccTransGetReadOnly(trans))
1484  return FALSE;
1485 
1486  xaccTransBeginEdit(trans);
1487  ed.node = split;
1488  ed.idx = xaccTransGetSplitIndex(trans, split);
1489  qof_instance_set_dirty(QOF_INSTANCE(split));
1490  qof_instance_set_destroying(split, TRUE);
1491  qof_event_gen(&trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1492  xaccTransCommitEdit(trans);
1493 
1494  return TRUE;
1495 }
1496 
1497 /********************************************************************\
1498 \********************************************************************/
1499 
1500 gint
1501 xaccSplitOrder (const Split *sa, const Split *sb)
1502 {
1503  int retval;
1504  int comp;
1505  const char *da, *db;
1506  gboolean action_for_num;
1507 
1508  if (sa == sb) return 0;
1509  /* nothing is always less than something */
1510  if (!sa) return -1;
1511  if (!sb) return +1;
1512 
1513  /* sort in transaction order, but use split action rather than trans num
1514  * according to book option */
1516  (xaccSplitGetBook (sa));
1517  if (action_for_num)
1518  retval = xaccTransOrder_num_action (sa->parent, sa->action,
1519  sb->parent, sb->action);
1520  else
1521  retval = xaccTransOrder (sa->parent, sb->parent);
1522  if (retval) return retval;
1523 
1524  /* otherwise, sort on memo strings */
1525  da = sa->memo ? sa->memo : "";
1526  db = sb->memo ? sb->memo : "";
1527  retval = g_utf8_collate (da, db);
1528  if (retval)
1529  return retval;
1530 
1531  /* otherwise, sort on action strings */
1532  da = sa->action ? sa->action : "";
1533  db = sb->action ? sb->action : "";
1534  retval = g_utf8_collate (da, db);
1535  if (retval != 0)
1536  return retval;
1537 
1538  /* the reconciled flag ... */
1539  if (sa->reconciled < sb->reconciled) return -1;
1540  if (sa->reconciled > sb->reconciled) return +1;
1541 
1542  /* compare amounts */
1544  if (comp < 0) return -1;
1545  if (comp > 0) return +1;
1546 
1548  if (comp < 0) return -1;
1549  if (comp > 0) return +1;
1550 
1551  /* if dates differ, return */
1552  if (sa->date_reconciled < sb->date_reconciled)
1553  return -1;
1554  else if (sa->date_reconciled > sb->date_reconciled)
1555  return 1;
1556 
1557  /* else, sort on guid - keeps sort stable. */
1558  retval = qof_instance_guid_compare(sa, sb);
1559  if (retval) return retval;
1560 
1561  return 0;
1562 }
1563 
1564 gint
1565 xaccSplitOrderDateOnly (const Split *sa, const Split *sb)
1566 {
1567  Transaction *ta, *tb;
1568 
1569  if (sa == sb) return 0;
1570  /* nothing is always less than something */
1571  if (!sa) return -1;
1572  if (!sb) return +1;
1573 
1574  ta = sa->parent;
1575  tb = sb->parent;
1576  if ( !ta && !tb ) return 0;
1577  if ( !tb ) return -1;
1578  if ( !ta ) return +1;
1579 
1580  if (ta->date_posted == tb->date_posted)
1581  return -1; // Keep the same order
1582  return (ta->date_posted > tb->date_posted) - (ta->date_posted < tb->date_posted);
1583 }
1584 
1585 static gboolean
1586 get_corr_account_split(const Split *sa, const Split **retval)
1587 {
1588  *retval = nullptr;
1589  g_return_val_if_fail(sa, FALSE);
1590 
1591  if (xaccTransCountSplits (sa->parent) > 2)
1592  return FALSE;
1593 
1594  *retval = xaccSplitGetOtherSplit (sa);
1595  if (*retval)
1596  return TRUE;
1597  else
1598  return FALSE;
1599 }
1600 
1601 /* TODO: these static consts can be shared. */
1602 const char *
1604 {
1605  static const char *split_const = nullptr;
1606  const Split *other_split;
1607 
1608  if (!get_corr_account_split(sa, &other_split))
1609  {
1610  if (!split_const)
1611  split_const = _("-- Split Transaction --");
1612 
1613  return split_const;
1614  }
1615 
1616  return xaccAccountGetName(other_split->acc);
1617 }
1618 
1619 char *
1621 {
1622  static const char *split_const = nullptr;
1623  const Split *other_split;
1624 
1625  if (!get_corr_account_split(sa, &other_split))
1626  {
1627  if (!split_const)
1628  split_const = _("-- Split Transaction --");
1629 
1630  return g_strdup(split_const);
1631  }
1632  return gnc_account_get_full_name(other_split->acc);
1633 }
1634 
1635 const char *
1637 {
1638  static const char *split_const = nullptr;
1639  const Split *other_split;
1640 
1641  if (!get_corr_account_split(sa, &other_split))
1642  {
1643  if (!split_const)
1644  split_const = C_("Displayed account code of the other account in a multi-split transaction", "Split");
1645 
1646  return split_const;
1647  }
1648  return xaccAccountGetCode(other_split->acc);
1649 }
1650 
1651 /* TODO: It's not too hard to make this function avoid the malloc/free. */
1652 int
1653 xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
1654 {
1655  Account *aa, *ab;
1656  if (sa == sb) return 0;
1657  if (!sa) return -1;
1658  if (!sb) return 1;
1659 
1660  aa = sa->acc;
1661  ab = sb->acc;
1662  if (aa == ab) return 0;
1663 
1664  auto path_a = gnc_account_get_all_parents (aa);
1665  auto path_b = gnc_account_get_all_parents (ab);
1666  auto mismatch_pair = std::mismatch (path_a.rbegin(), path_a.rend(),
1667  path_b.rbegin(), path_b.rend());
1668 
1669  return mismatch_pair.first == path_a.rend() ? -1
1670  : mismatch_pair.second == path_b.rend() ? 1
1671  : g_utf8_collate (xaccAccountGetName (*mismatch_pair.first),
1672  xaccAccountGetName (*mismatch_pair.second));
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 : nullptr;
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  qof_instance_set_dirty(QOF_INSTANCE(s));
1865 
1866  xaccTransCommitEdit(old_trans);
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 (nullptr == 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 : nullptr;
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 : nullptr;
1903 }
1904 
1905 void
1906 xaccSplitSetOnlineID (Split *split, const char *id)
1907 {
1908  if (!split) return;
1909  /* No xaccTransBeginEdit/CommitEdit here: the online_id is normally set
1910  * while many other parameters of a transaction are being changed, so
1911  * the caller wraps this in the parent transaction's edit. */
1912  std::optional<const char*> val;
1913  if (id && *id)
1914  val = g_strdup (id);
1915  qof_instance_set_path_kvp<const char*> (QOF_INSTANCE(split), val, {split_online_id});
1916  qof_instance_set_dirty (QOF_INSTANCE(split));
1917 }
1918 
1919 const char *
1920 xaccSplitGetOnlineID (const Split *split)
1921 {
1922  if (!split) return nullptr;
1923  auto rv{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(split), {split_online_id})};
1924  return rv ? *rv : nullptr;
1925 }
1926 
1927 gboolean
1928 xaccSplitHasOnlineID (const Split *split)
1929 {
1930  auto id = xaccSplitGetOnlineID (split);
1931  return (id && *id);
1932 }
1933 
1934 const char *
1935 xaccSplitGetAction (const Split *split)
1936 {
1937  return split ? split->action : nullptr;
1938 }
1939 
1940 char
1941 xaccSplitGetReconcile (const Split *split)
1942 {
1943  return split ? split->reconciled : ' ';
1944 }
1945 
1946 
1947 gnc_numeric
1948 xaccSplitGetAmount (const Split * split)
1949 {
1950  return split ? split->amount : gnc_numeric_zero();
1951 }
1952 
1953 gnc_numeric
1954 xaccSplitGetValue (const Split * split)
1955 {
1956  return split ? split->value : gnc_numeric_zero();
1957 }
1958 
1959 gnc_numeric
1960 xaccSplitGetSharePrice (const Split * split)
1961 {
1962  gnc_numeric amt, val, price;
1963  if (!split) return gnc_numeric_create(0, 1);
1964 
1965 
1966  /* if amount == 0, return 0
1967  * otherwise return value/amount
1968  */
1969 
1970  amt = xaccSplitGetAmount(split);
1971  val = xaccSplitGetValue(split);
1972  if (gnc_numeric_zero_p(amt))
1973  return gnc_numeric_create(0, 1);
1974 
1975  price = gnc_numeric_div(val, amt,
1978 
1979  /* During random checks we can get some very weird prices. Let's
1980  * handle some overflow and other error conditions by returning
1981  * zero. But still print an error to let us know it happened.
1982  */
1983  if (gnc_numeric_check(price))
1984  {
1985  PERR("Computing share price failed (%d): [ %" G_GINT64_FORMAT " / %"
1986  G_GINT64_FORMAT " ] / [ %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " ]",
1987  gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
1988  return gnc_numeric_create(0, 1);
1989  }
1990 
1991  return price;
1992 }
1993 
1994 /********************************************************************\
1995 \********************************************************************/
1996 
1997 QofBook *
1998 xaccSplitGetBook (const Split *split)
1999 {
2000  return qof_instance_get_book(QOF_INSTANCE(split));
2001 }
2002 
2003 const char *
2004 xaccSplitGetType(const Split *s)
2005 {
2006  if (!s) return nullptr;
2007 
2008  auto type{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(s), {"split-type"})};
2009 
2010  if (!type || !g_strcmp0 (*type, split_type_normal))
2011  return split_type_normal;
2012 
2013  if (!g_strcmp0 (*type, split_type_stock_split))
2014  return split_type_stock_split;
2015 
2016  PERR ("unexpected split-type %s, reset to normal.", *type);
2017  return split_type_normal;
2018 }
2019 
2020 /* reconfigure a split to be a stock split - after this, you shouldn't
2021  mess with the value, just the amount. */
2022 void
2024 {
2025  xaccTransBeginEdit (s->parent);
2026 
2027  s->value = gnc_numeric_zero();
2028  qof_instance_set_path_kvp<const char*> (QOF_INSTANCE(s), g_strdup(split_type_stock_split),
2029  {"split-type"});
2030  SET_GAINS_VDIRTY(s);
2031  mark_split(s);
2032  qof_instance_set_dirty(QOF_INSTANCE(s));
2033  xaccTransCommitEdit(s->parent);
2034 }
2035 
2036 void
2037 xaccSplitAddPeerSplit (Split *split, const Split *other_split,
2038  time64 timestamp)
2039 {
2040  const GncGUID* guid;
2041 
2042  g_return_if_fail (split != nullptr);
2043  g_return_if_fail (other_split != nullptr);
2044 
2045  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2046  xaccTransBeginEdit (split->parent);
2047  qof_instance_kvp_add_guid (QOF_INSTANCE (split), "lot-split",
2048  gnc_time(nullptr), "peer_guid", guid_copy(guid));
2049  mark_split (split);
2050  qof_instance_set_dirty (QOF_INSTANCE (split));
2051  xaccTransCommitEdit (split->parent);
2052 }
2053 
2054 gboolean
2055 xaccSplitHasPeers (const Split *split)
2056 {
2057  return qof_instance_has_slot (QOF_INSTANCE (split), "lot-split");
2058 }
2059 
2060 gboolean
2061 xaccSplitIsPeerSplit (const Split *split, const Split *other_split)
2062 {
2063  const GncGUID* guid;
2064 
2065  g_return_val_if_fail (split != nullptr, FALSE);
2066  g_return_val_if_fail (other_split != nullptr, FALSE);
2067 
2068  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2069  return qof_instance_kvp_has_guid (QOF_INSTANCE (split), "lot-split",
2070  "peer_guid", guid);
2071 }
2072 
2073 void
2074 xaccSplitRemovePeerSplit (Split *split, const Split *other_split)
2075 {
2076  const GncGUID* guid;
2077 
2078  g_return_if_fail (split != nullptr);
2079  g_return_if_fail (other_split != nullptr);
2080 
2081  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2082  xaccTransBeginEdit (split->parent);
2083  qof_instance_kvp_remove_guid (QOF_INSTANCE (split), "lot-split",
2084  "peer_guid", guid);
2085  mark_split (split);
2086  qof_instance_set_dirty (QOF_INSTANCE (split));
2087  xaccTransCommitEdit (split->parent);
2088 }
2089 
2090 void
2091 xaccSplitMergePeerSplits (Split *split, const Split *other_split)
2092 {
2093  xaccTransBeginEdit (split->parent);
2094  qof_instance_kvp_merge_guids (QOF_INSTANCE (split),
2095  QOF_INSTANCE (other_split), "lot-split");
2096  mark_split (split);
2097  qof_instance_set_dirty (QOF_INSTANCE (split));
2098  xaccTransCommitEdit (split->parent);
2099 }
2100 
2101 /********************************************************************\
2102 \********************************************************************/
2103 /* In the old world, the 'other split' was the other split of a
2104  * transaction that contained only two splits. In the new world,
2105  * a split may have been cut up between multiple lots, although
2106  * in a conceptual sense, if lots hadn't been used, there would be
2107  * only a pair. So we handle this conceptual case: we can still
2108  * identify, unambiguously, the 'other' split when 'this' split
2109  * as been cut up across lots. We do this by looking for the
2110  * 'lot-split' keyword, which occurs only in cut-up splits.
2111  */
2112 
2113 Split *
2114 xaccSplitGetOtherSplit (const Split *split)
2115 {
2116  Transaction *trans;
2117  Split *other = nullptr;
2118 
2119  if (!split) return nullptr;
2120  trans = split->parent;
2121  if (!trans) return nullptr;
2122 
2123  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
2124  {
2125  Split *s = GNC_SPLIT(n->data);
2126  if ((s == split) ||
2127  (!xaccTransStillHasSplit(trans, s)) ||
2129  (qof_instance_has_slot (QOF_INSTANCE (s), "lot-split")))
2130  continue;
2131 
2132  if (other)
2133  return nullptr;
2134 
2135  other = s;
2136  }
2137  return other;
2138 }
2139 
2140 /********************************************************************\
2141 \********************************************************************/
2142 
2143 gnc_numeric
2144 xaccSplitVoidFormerAmount(const Split *split)
2145 {
2146  g_return_val_if_fail(split, gnc_numeric_zero());
2147  auto num{qof_instance_get_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {void_former_amt_str})};
2148  return num ? *num : gnc_numeric_zero();
2149 }
2150 
2151 gnc_numeric
2152 xaccSplitVoidFormerValue(const Split *split)
2153 {
2154  g_return_val_if_fail(split, gnc_numeric_zero());
2155  auto num{qof_instance_get_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {void_former_val_str})};
2156  return num ? *num : gnc_numeric_zero();
2157 }
2158 
2159 void
2160 xaccSplitVoid(Split *split)
2161 {
2162  g_return_if_fail (GNC_IS_SPLIT(split));
2163  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), xaccSplitGetAmount(split), {void_former_amt_str});
2164  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), xaccSplitGetValue(split), {void_former_val_str});
2165  qof_instance_set_dirty (QOF_INSTANCE(split));
2166 
2167  static gnc_numeric zero = gnc_numeric_zero();
2168  xaccSplitSetAmount (split, zero);
2169  xaccSplitSetValue (split, zero);
2170  xaccSplitSetReconcile(split, VREC);
2171 }
2172 
2173 void
2174 xaccSplitUnvoid(Split *split)
2175 {
2176  g_return_if_fail (GNC_IS_SPLIT(split));
2179  xaccSplitSetReconcile(split, NREC);
2180  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {}, {void_former_amt_str});
2181  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {}, {void_former_val_str});
2182  qof_instance_set_dirty (QOF_INSTANCE(split));
2183 }
2184 
2185 /********************************************************************\
2186 \********************************************************************/
2187 /* QofObject function implementation */
2188 
2189 /* Hook into the QofObject registry */
2190 
2191 #ifdef _MSC_VER
2192 /* MSVC compiler doesn't have C99 "designated initializers"
2193  * so we wrap them in a macro that is empty on MSVC. */
2194 # define DI(x) /* */
2195 #else
2196 # define DI(x) x
2197 #endif
2198 static QofObject split_object_def =
2199 {
2200  DI(.interface_version = ) QOF_OBJECT_VERSION,
2201  DI(.e_type = ) GNC_ID_SPLIT,
2202  DI(.type_label = ) "Split",
2203  DI(.create = ) (void* (*)(QofBook*))xaccMallocSplit,
2204  DI(.book_begin = ) nullptr,
2205  DI(.book_end = ) nullptr,
2206  DI(.is_dirty = ) qof_collection_is_dirty,
2207  DI(.mark_clean = ) qof_collection_mark_clean,
2208  DI(.foreach = ) qof_collection_foreach,
2209  DI(.printable = ) (const char * (*)(gpointer)) xaccSplitGetMemo,
2210  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
2211 };
2212 
2213 static gpointer
2214 split_account_guid_getter (gpointer obj, const QofParam *p)
2215 {
2216  Split *s = GNC_SPLIT(obj);
2217  Account *acc;
2218 
2219  if (!s) return nullptr;
2220  acc = xaccSplitGetAccount (s);
2221  if (!acc) return nullptr;
2222  return ((gpointer)xaccAccountGetGUID (acc));
2223 }
2224 
2225 static double /* internal use only */
2226 DxaccSplitGetShareAmount (const Split * split)
2227 {
2228  return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
2229 }
2230 
2231 static gpointer
2232 no_op (gpointer obj, const QofParam *p)
2233 {
2234  return obj;
2235 }
2236 
2237 static void
2238 qofSplitSetParentTrans(Split *s, QofInstance *ent)
2239 {
2240  Transaction *trans = (Transaction*)ent;
2241 
2242  g_return_if_fail(trans);
2243  xaccSplitSetParent(s, trans);
2244 }
2245 
2246 static void
2247 qofSplitSetAccount(Split *s, QofInstance *ent)
2248 {
2249  Account *acc = (Account*)ent;
2250 
2251  g_return_if_fail(acc);
2252  xaccSplitSetAccount(s, acc);
2253 }
2254 
2255 gboolean xaccSplitRegister (void)
2256 {
2257  static const QofParam params[] =
2258  {
2259  {
2260  SPLIT_DATE_RECONCILED, QOF_TYPE_DATE,
2263  },
2264 
2265  /* d-* are deprecated query params, should not be used in new
2266  * queries, should be removed from old queries. */
2267  {
2268  "d-share-amount", QOF_TYPE_DOUBLE,
2269  (QofAccessFunc)DxaccSplitGetShareAmount, nullptr
2270  },
2271  {
2272  "d-share-int64", QOF_TYPE_INT64,
2274  },
2275  {
2276  SPLIT_BALANCE, QOF_TYPE_NUMERIC,
2278  },
2279  {
2280  SPLIT_CLEARED_BALANCE, QOF_TYPE_NUMERIC,
2282  },
2283  {
2284  SPLIT_RECONCILED_BALANCE, QOF_TYPE_NUMERIC,
2286  },
2287  {
2288  SPLIT_MEMO, QOF_TYPE_STRING,
2289  (QofAccessFunc)xaccSplitGetMemo, (QofSetterFunc)qofSplitSetMemo
2290  },
2291  {
2292  SPLIT_ACTION, QOF_TYPE_STRING,
2293  (QofAccessFunc)xaccSplitGetAction, (QofSetterFunc)qofSplitSetAction
2294  },
2295  {
2296  SPLIT_RECONCILE, QOF_TYPE_CHAR,
2298  (QofSetterFunc)qofSplitSetReconcile
2299  },
2300  {
2301  SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
2302  (QofAccessFunc)xaccSplitGetAmount, (QofSetterFunc)qofSplitSetAmount
2303  },
2304  {
2305  SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
2307  (QofSetterFunc)qofSplitSetSharePrice
2308  },
2309  {
2310  SPLIT_VALUE, QOF_TYPE_DEBCRED,
2311  (QofAccessFunc)xaccSplitGetValue, (QofSetterFunc)qofSplitSetValue
2312  },
2313  { SPLIT_TYPE, QOF_TYPE_STRING, (QofAccessFunc)xaccSplitGetType, nullptr },
2314  {
2315  SPLIT_VOIDED_AMOUNT, QOF_TYPE_NUMERIC,
2317  },
2318  {
2319  SPLIT_VOIDED_VALUE, QOF_TYPE_NUMERIC,
2321  },
2322  { SPLIT_LOT, GNC_ID_LOT, (QofAccessFunc)xaccSplitGetLot, nullptr },
2323  {
2324  SPLIT_TRANS, GNC_ID_TRANS,
2326  (QofSetterFunc)qofSplitSetParentTrans
2327  },
2328  {
2329  SPLIT_ACCOUNT, GNC_ID_ACCOUNT,
2330  (QofAccessFunc)xaccSplitGetAccount, (QofSetterFunc)qofSplitSetAccount
2331  },
2332  { SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, nullptr },
2333  /* these are no-ops to register the parameter names (for sorting) but
2334  they return an allocated object which getters cannot do. */
2335  { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, nullptr },
2336  { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, nullptr },
2337  { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, nullptr },
2338  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, nullptr },
2339  {
2340  QOF_PARAM_GUID, QOF_TYPE_GUID,
2342  },
2343  { nullptr },
2344  };
2345 
2346  qof_class_register (GNC_ID_SPLIT, (QofSortFunc)xaccSplitOrder, params);
2347  qof_class_register (SPLIT_ACCT_FULLNAME,
2349  qof_class_register (SPLIT_CORR_ACCT_NAME,
2351  nullptr);
2352  qof_class_register (SPLIT_CORR_ACCT_CODE,
2354 
2355  return qof_object_register (&split_object_def);
2356 }
2357 
2359 _utest_split_fill_functions (void)
2360 {
2361  SplitTestFunctions *func = g_new (SplitTestFunctions, 1);
2362 
2363  func->xaccSplitEqualCheckBal = xaccSplitEqualCheckBal;
2364  func->get_currency_denom = get_currency_denom;
2365  func->get_commodity_denom = get_commodity_denom;
2366  func->get_corr_account_split = get_corr_account_split;
2367  return func;
2368 }
2369 
2370 /************************ END OF ************************************\
2371 \************************* 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.cpp:1260
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.cpp:1308
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition: Split.cpp:1501
This is the private header for the account structure.
void xaccSplitAddPeerSplit(Split *split, const Split *other_split, time64 timestamp)
Add a peer split to this split&#39;s lot-split list.
Definition: Split.cpp:2037
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.cpp:1320
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition: Split.cpp:1751
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
void xaccSplitMakeStockSplit(Split *s)
Mark a split to be of type stock split - after this, you shouldn&#39;t modify the value anymore...
Definition: Split.cpp:2023
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.cpp:1677
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
#define qof_instance_is_dirty
Return value of is_dirty flag.
Definition: qofinstance.h:166
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:232
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:209
#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.cpp:1314
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3248
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1471
gboolean xaccSplitHasOnlineID(const Split *split)
Returns TRUE if the split has a non-empty online_id.
Definition: Split.cpp:1928
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:2726
const char * xaccAccountGetCode(const Account *acc)
Get the account&#39;s accounting code.
Definition: Account.cpp:3317
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
STRUCTS.
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition: guid.cpp:155
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
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.cpp:640
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
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.cpp:1941
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)
Adds a split to this lot.
Definition: gnc-lot.cpp:579
gboolean gnc_account_remove_split(Account *acc, Split *s)
Remove the given split from an account.
Definition: Account.cpp:1971
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Object instance holds common fields that most gnucash objects use.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Definition: Split.cpp:1784
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2138
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition: Split.cpp: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:208
void xaccSplitRemovePeerSplit(Split *split, const Split *other_split)
Remove a peer split from this split&#39;s lot-split list.
Definition: Split.cpp:2074
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:168
gint 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.
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:63
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.cpp: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.cpp:1998
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.
const char * xaccSplitGetOnlineID(const Split *split)
Returns the split&#39;s online_id.
Definition: Split.cpp:1920
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gnc_numeric xaccSplitGetBalance(const Split *s)
Returns the running balance up to and including the indicated split.
Definition: Split.cpp:1296
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:108
Split * xaccSplitGetCapGainsSplit(const Split *split)
The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split...
Definition: cap-gains.cpp:480
void gnc_lot_set_closed_unknown(GNCLot *lot)
Reset closed flag so that it will be recalculated.
Definition: gnc-lot.cpp:414
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:130
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.cpp:1653
#define VREC
split is void
Definition: Split.h:77
Account used to record multiple commodity transactions.
Definition: Account.h:155
gboolean xaccSplitEqual(const Split *sa, const Split *sb, gboolean check_guids, gboolean check_balances, gboolean check_txn_splits)
Equality.
Definition: Split.cpp:803
gboolean xaccSplitHasPeers(const Split *split)
Does this split have peers?
Definition: Split.cpp:2055
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.
#define xaccAccountGetGUID(X)
Definition: Account.h:252
gdouble gnc_numeric_to_double(gnc_numeric n)
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.cpp:2091
gnc_numeric xaccSplitVoidFormerAmount(const Split *split)
Returns the original pre-void amount of a split.
Definition: Split.cpp:2144
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.cpp: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.cpp:1224
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:3286
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_guids, gboolean check_splits, gboolean check_balances, gboolean assume_ordered)
Equality.
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.cpp:2152
Account public routines (C++ api)
#define YREC
The Split has been reconciled.
Definition: Split.h:74
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.cpp: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:75
int xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
Compare two splits by code of the other account.
Definition: Split.cpp: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.cpp:1158
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.cpp:1302
#define SPLIT_ACCOUNT_GUID
for guid_match_all
Definition: Split.h:563
void xaccAccountRecomputeBalance(Account *acc)
The following recompute the partial balances (stored with the transaction) and the total balance...
Definition: Account.cpp:2277
gboolean xaccSplitIsPeerSplit(const Split *split, const Split *other_split)
Report if a split is a peer of this one.
Definition: Split.cpp:2061
char * xaccSplitGetCorrAccountFullName(const Split *sa)
These functions take a split, get the corresponding split on the "other side" of the transaction...
Definition: Split.cpp:1620
void gnc_lot_remove_split(GNCLot *lot, Split *split)
Adds a split from this lot.
Definition: gnc-lot.cpp:631
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:123
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition: gnc-date.h:108
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:238
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 x, gnc_numeric y, gint64 denom, gint how)
Division.
#define xaccSplitGetGUID(X)
Definition: Split.h:571
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.cpp:1960
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
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:73
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.cpp:1375
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: Split.cpp:533
const char * xaccSplitGetCorrAccountName(const Split *sa)
document me
Definition: Split.cpp:1603
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:1941
void xaccSplitSetLot(Split *split, GNCLot *lot)
Assigns the split to a specific Lot.
Definition: Split.cpp:1891
API for the transaction logger.
QofBook reference.
Definition: qofbook-p.hpp:46
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.cpp:1810
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition: Split.cpp:1824
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: Split.cpp:1954
Account * xaccSplitGetAccount(const Split *s)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: Split.cpp:937
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3389
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1065
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
void xaccSplitSetOnlineID(Split *split, const char *id)
The online_id is the OFX/HBCI "FITID" recorded on a split when it is imported.
Definition: Split.cpp:1906
const char * xaccSplitGetCorrAccountCode(const Split *sa)
document me
Definition: Split.cpp:1636
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
Definition: Split.cpp:2114
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
void xaccSplitSetSharePrice(Split *s, gnc_numeric price)
Definition: Split.cpp:1186
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:262
int xaccTransOrder(const Transaction *ta, const Transaction *tb)
The xaccTransOrder(ta,tb) method is useful for sorting.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: Split.cpp:1900
const char * xaccSplitGetAction(const Split *split)
Returns the action string.
Definition: Split.cpp:1935
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:521
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition: gnc-lot.cpp:377
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:299
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.cpp:2004
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3270
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:223
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
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:574
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.cpp:1885
#define NREC
not reconciled or cleared
Definition: Split.h:76
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: Split.cpp:1948