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