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 
1114  if (GAINS_STATUS_UNKNOWN != split->gains) return;
1115 
1116  /* A gains source has a forward "gains-split" link to the split that
1117  * records its gains. */
1118  other = xaccSplitGetCapGainsSplit (split);
1119  if (other)
1120  {
1121  split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1122  split->gains_split = other;
1123  /* Resolve the gains-recording split too, so it reuses this link
1124  * rather than being re-created if it is processed first. */
1125  if (GAINS_STATUS_UNKNOWN == other->gains)
1126  {
1127  other->gains = GAINS_STATUS_GAINS;
1128  other->gains_split = split;
1129  }
1130  return;
1131  }
1132 
1133  /* A gains-recording split has a backward "gains-source" link to the
1134  * split whose gains it records. */
1135  other = xaccSplitGetGainsSourceSplit (split);
1136  if (!other)
1137  {
1138  // CHECKME: We leave split->gains_split alone. Is that correct?
1139  split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1140  }
1141  else
1142  {
1143  split->gains = GAINS_STATUS_GAINS;
1144  split->gains_split = other;
1145  /* Resolve the source too, so it reuses this split rather than
1146  * creating a duplicate if the source is processed afterward. */
1147  if (GAINS_STATUS_UNKNOWN == other->gains)
1148  {
1149  other->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1150  other->gains_split = split;
1151  }
1152  }
1153 }
1154 
1155 /********************************************************************\
1156 \********************************************************************/
1157 
1158 static inline int
1159 get_currency_denom(const Split * s)
1160 {
1161  if (!(s && s->parent && s->parent->common_currency))
1162  {
1163  return GNC_DENOM_AUTO;
1164  }
1165  else
1166  {
1167  return gnc_commodity_get_fraction (s->parent->common_currency);
1168  }
1169 }
1170 
1171 static inline int
1172 get_commodity_denom(const Split * s)
1173 {
1174  if (!(s && s->acc))
1175  {
1176  return GNC_DENOM_AUTO;
1177  }
1178  else
1179  {
1180  return xaccAccountGetCommoditySCU(s->acc);
1181  }
1182 }
1183 
1184 /********************************************************************\
1185 \********************************************************************/
1186 
1187 void
1188 xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)
1189 {
1190  if (!s) return;
1191  ENTER (" ");
1192  xaccTransBeginEdit (s->parent);
1193 
1194  s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1196  s->value = gnc_numeric_mul(s->amount, price,
1197  get_currency_denom(s), GNC_HOW_RND_ROUND_HALF_UP);
1198 
1199  SET_GAINS_A_VDIRTY(s);
1200  mark_split (s);
1201  qof_instance_set_dirty(QOF_INSTANCE(s));
1202  xaccTransCommitEdit(s->parent);
1203  LEAVE ("");
1204 }
1205 
1206 static void
1207 qofSplitSetSharePrice (Split *split, gnc_numeric price)
1208 {
1209  g_return_if_fail(split);
1210  split->value = gnc_numeric_mul(xaccSplitGetAmount(split),
1211  price, get_currency_denom(split),
1213 }
1214 
1215 void
1216 xaccSplitSetSharePrice (Split *s, gnc_numeric price)
1217 {
1218  if (!s) return;
1219 
1220  if (gnc_numeric_zero_p (price))
1221  return;
1222 
1223  ENTER (" ");
1224  xaccTransBeginEdit (s->parent);
1225 
1226  s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
1227  price, get_currency_denom(s),
1229 
1230  SET_GAINS_VDIRTY(s);
1231  mark_split (s);
1232  qof_instance_set_dirty(QOF_INSTANCE(s));
1233  xaccTransCommitEdit(s->parent);
1234  LEAVE ("");
1235 }
1236 
1237 static void
1238 qofSplitSetAmount (Split *split, gnc_numeric amt)
1239 {
1240  g_return_if_fail(split);
1241  if (split->acc)
1242  {
1243  split->amount = gnc_numeric_convert(amt,
1244  get_commodity_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1245  }
1246  else
1247  {
1248  split->amount = amt;
1249  }
1250 }
1251 
1252 /* The amount of the split in the _account's_ commodity. */
1253 void
1254 xaccSplitSetAmount (Split *s, gnc_numeric amt)
1255 {
1256  if (!s) return;
1257  g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1258  ENTER ("(split=%p) old amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1259  " new amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1260  s->amount.num, s->amount.denom, amt.num, amt.denom);
1261 
1262  xaccTransBeginEdit (s->parent);
1263  if (s->acc)
1264  {
1265  s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1267  g_assert (gnc_numeric_check (s->amount) == GNC_ERROR_OK);
1268  }
1269  else
1270  s->amount = amt;
1271  s->adjusted_amount = s->amount;
1272 
1273  SET_GAINS_ADIRTY(s);
1274  mark_split (s);
1275  qof_instance_set_dirty(QOF_INSTANCE(s));
1276  xaccTransCommitEdit(s->parent);
1277  LEAVE("");
1278 }
1279 
1280 static void
1281 qofSplitSetValue (Split *split, gnc_numeric amt)
1282 {
1283  g_return_if_fail(split);
1284  split->value = gnc_numeric_convert(amt,
1285  get_currency_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1286  g_assert(gnc_numeric_check (split->value) != GNC_ERROR_OK);
1287 }
1288 
1289 /* The value of the split in the _transaction's_ currency. */
1290 void
1291 xaccSplitSetValue (Split *s, gnc_numeric amt)
1292 {
1293  gnc_numeric new_val;
1294  if (!s) return;
1295 
1296  g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1297  ENTER ("(split=%p) old val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1298  " new val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1299  s->value.num, s->value.denom, amt.num, amt.denom);
1300 
1301  xaccTransBeginEdit (s->parent);
1302  new_val = gnc_numeric_convert(amt, get_currency_denom(s),
1304  if (gnc_numeric_check(new_val) == GNC_ERROR_OK &&
1305  !(gnc_numeric_zero_p (new_val) && !gnc_numeric_zero_p (amt)))
1306  {
1307  s->value = new_val;
1308  }
1309  else
1310  {
1311  PERR("numeric error %s in converting the split value's denominator with amount %s and denom %d",
1313  gnc_num_dbg_to_string (amt), get_currency_denom(s));
1314  }
1315 
1316  SET_GAINS_VDIRTY(s);
1317  mark_split (s);
1318  qof_instance_set_dirty(QOF_INSTANCE(s));
1319  xaccTransCommitEdit(s->parent);
1320  LEAVE ("");
1321 }
1322 
1323 /********************************************************************\
1324 \********************************************************************/
1325 
1326 gnc_numeric
1327 xaccSplitGetBalance (const Split *s)
1328 {
1329  return s ? s->balance : gnc_numeric_zero();
1330 }
1331 
1332 gnc_numeric
1334 {
1335  return s ? s->noclosing_balance : gnc_numeric_zero();
1336 }
1337 
1338 gnc_numeric
1340 {
1341  return s ? s->cleared_balance : gnc_numeric_zero();
1342 }
1343 
1344 gnc_numeric
1346 {
1347  return s ? s->reconciled_balance : gnc_numeric_zero();
1348 }
1349 
1350 gnc_numeric
1352 {
1353  return s ? s->adjusted_amount : gnc_numeric_zero();
1354 }
1355 
1356 void
1357 xaccSplitSetAdjustedAmount (Split *s, gnc_numeric amt)
1358 {
1359  if (!s) return;
1360  if (gnc_numeric_check (amt)) return;
1361 
1362  s->adjusted_amount = amt;
1363 }
1364 
1365 void
1366 xaccSplitSetBaseValue (Split *s, gnc_numeric value,
1367  const gnc_commodity * base_currency)
1368 {
1369  const gnc_commodity *currency;
1370  const gnc_commodity *commodity;
1371 
1372  if (!s) return;
1373  xaccTransBeginEdit (s->parent);
1374 
1375  if (!s->acc)
1376  {
1377  PERR ("split must have a parent account");
1378  return;
1379  }
1380 
1381  currency = xaccTransGetCurrency (s->parent);
1382  commodity = xaccAccountGetCommodity (s->acc);
1383 
1384  /* If the base_currency is the transaction's commodity ('currency'),
1385  * set the value. If it's the account commodity, set the
1386  * amount. If both, set both. */
1387  if (gnc_commodity_equiv(currency, base_currency))
1388  {
1389  if (gnc_commodity_equiv(commodity, base_currency))
1390  {
1391  s->amount = gnc_numeric_convert(value,
1392  get_commodity_denom(s),
1394  }
1395  s->value = gnc_numeric_convert(value,
1396  get_currency_denom(s),
1398  }
1399  else if (gnc_commodity_equiv(commodity, base_currency))
1400  {
1401  s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
1403  }
1404  else
1405  {
1406  PERR ("inappropriate base currency %s "
1407  "given split currency=%s and commodity=%s\n",
1408  gnc_commodity_get_printname(base_currency),
1409  gnc_commodity_get_printname(currency),
1410  gnc_commodity_get_printname(commodity));
1411  return;
1412  }
1413 
1414  SET_GAINS_A_VDIRTY(s);
1415  mark_split (s);
1416  qof_instance_set_dirty(QOF_INSTANCE(s));
1417  xaccTransCommitEdit(s->parent);
1418 }
1419 
1420 gnc_numeric
1421 xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)
1422 {
1423  if (!s || !s->acc || !s->parent) return gnc_numeric_zero();
1424 
1425  /* be more precise -- the value depends on the currency we want it
1426  * expressed in. */
1427  if (gnc_commodity_equiv(xaccTransGetCurrency(s->parent), base_currency))
1428  return xaccSplitGetValue(s);
1429  if (gnc_commodity_equiv(xaccAccountGetCommodity(s->acc), base_currency))
1430  return xaccSplitGetAmount(s);
1431 
1432  PERR ("inappropriate base currency %s "
1433  "given split currency=%s and commodity=%s\n",
1434  gnc_commodity_get_printname(base_currency),
1437  return gnc_numeric_zero();
1438 }
1439 
1440 /********************************************************************\
1441 \********************************************************************/
1442 
1443 gnc_numeric
1444 xaccSplitConvertAmount (const Split *split, const Account * account)
1445 {
1446  gnc_commodity *acc_com, *to_commodity;
1447  Transaction *txn;
1448  gnc_numeric amount, value, convrate;
1449  Account * split_acc;
1450 
1451  amount = xaccSplitGetAmount (split);
1452 
1453  /* If this split is attached to this account, OR */
1454  split_acc = xaccSplitGetAccount (split);
1455  if (split_acc == account)
1456  return amount;
1457 
1458  /* If split->account->commodity == to_commodity, return the amount */
1459  acc_com = xaccAccountGetCommodity (split_acc);
1460  to_commodity = xaccAccountGetCommodity (account);
1461  if (acc_com && gnc_commodity_equal (acc_com, to_commodity))
1462  return amount;
1463 
1464  /* Ok, this split is not for the viewed account, and the commodity
1465  * does not match. So we need to do some conversion.
1466  *
1467  * First, we can cheat. If this transaction is balanced and has
1468  * exactly two splits, then we can implicitly determine the exchange
1469  * rate and just return the 'other' split amount.
1470  */
1471  txn = xaccSplitGetParent (split);
1472  if (txn && xaccTransIsBalanced (txn))
1473  {
1474  const Split *osplit = xaccSplitGetOtherSplit (split);
1475 
1476  if (osplit)
1477  {
1478  gnc_commodity* split_comm =
1480  if (!gnc_commodity_equal(to_commodity, split_comm))
1481  {
1482  gchar guidstr[GUID_ENCODING_LENGTH+1];
1483  guid_to_string_buff(xaccSplitGetGUID(osplit),guidstr);
1484  PERR("The split's (%s) amount can't be converted from %s into %s.",
1485  guidstr,
1486  gnc_commodity_get_mnemonic(split_comm),
1487  gnc_commodity_get_mnemonic(to_commodity)
1488  );
1489  return gnc_numeric_zero();
1490  }
1491  return gnc_numeric_neg (xaccSplitGetAmount (osplit));
1492  }
1493  }
1494 
1495  /* ... otherwise, we need to compute the amount from the conversion
1496  * rate into _this account_. So, find the split into this account,
1497  * compute the conversion rate (based on amount/value), and then multiply
1498  * this times the split value.
1499  */
1500  value = xaccSplitGetValue (split);
1501 
1502  if (gnc_numeric_zero_p (value))
1503  {
1504  return value;
1505  }
1506 
1507  convrate = xaccTransGetAccountConvRate(txn, account);
1508  return gnc_numeric_mul (value, convrate,
1509  gnc_commodity_get_fraction (to_commodity),
1511 }
1512 
1513 /********************************************************************\
1514 \********************************************************************/
1515 
1516 gboolean
1517 xaccSplitDestroy (Split *split)
1518 {
1519  Account *acc;
1520  Transaction *trans;
1521  GncEventData ed;
1522 
1523  if (!split) return TRUE;
1524 
1525  acc = split->acc;
1526  trans = split->parent;
1527  if (acc && !qof_instance_get_destroying(acc)
1528  && !qof_instance_get_destroying(trans)
1529  && xaccTransGetReadOnly(trans))
1530  return FALSE;
1531 
1532  xaccTransBeginEdit(trans);
1533  ed.node = split;
1534  ed.idx = xaccTransGetSplitIndex(trans, split);
1535  qof_instance_set_dirty(QOF_INSTANCE(split));
1536  qof_instance_set_destroying(split, TRUE);
1537  qof_event_gen(&trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1538  xaccTransCommitEdit(trans);
1539 
1540  return TRUE;
1541 }
1542 
1543 /********************************************************************\
1544 \********************************************************************/
1545 
1546 gint
1547 xaccSplitOrder (const Split *sa, const Split *sb)
1548 {
1549  int retval;
1550  int comp;
1551  const char *da, *db;
1552  gboolean action_for_num;
1553 
1554  if (sa == sb) return 0;
1555  /* nothing is always less than something */
1556  if (!sa) return -1;
1557  if (!sb) return +1;
1558 
1559  /* sort in transaction order, but use split action rather than trans num
1560  * according to book option */
1562  (xaccSplitGetBook (sa));
1563  if (action_for_num)
1564  retval = xaccTransOrder_num_action (sa->parent, sa->action,
1565  sb->parent, sb->action);
1566  else
1567  retval = xaccTransOrder (sa->parent, sb->parent);
1568  if (retval) return retval;
1569 
1570  /* otherwise, sort on memo strings */
1571  da = sa->memo ? sa->memo : "";
1572  db = sb->memo ? sb->memo : "";
1573  retval = g_utf8_collate (da, db);
1574  if (retval)
1575  return retval;
1576 
1577  /* otherwise, sort on action strings */
1578  da = sa->action ? sa->action : "";
1579  db = sb->action ? sb->action : "";
1580  retval = g_utf8_collate (da, db);
1581  if (retval != 0)
1582  return retval;
1583 
1584  /* the reconciled flag ... */
1585  if (sa->reconciled < sb->reconciled) return -1;
1586  if (sa->reconciled > sb->reconciled) return +1;
1587 
1588  /* compare amounts */
1590  if (comp < 0) return -1;
1591  if (comp > 0) return +1;
1592 
1594  if (comp < 0) return -1;
1595  if (comp > 0) return +1;
1596 
1597  /* if dates differ, return */
1598  if (sa->date_reconciled < sb->date_reconciled)
1599  return -1;
1600  else if (sa->date_reconciled > sb->date_reconciled)
1601  return 1;
1602 
1603  /* else, sort on guid - keeps sort stable. */
1604  retval = qof_instance_guid_compare(sa, sb);
1605  if (retval) return retval;
1606 
1607  return 0;
1608 }
1609 
1610 gint
1611 xaccSplitOrderDateOnly (const Split *sa, const Split *sb)
1612 {
1613  Transaction *ta, *tb;
1614 
1615  if (sa == sb) return 0;
1616  /* nothing is always less than something */
1617  if (!sa) return -1;
1618  if (!sb) return +1;
1619 
1620  ta = sa->parent;
1621  tb = sb->parent;
1622  if ( !ta && !tb ) return 0;
1623  if ( !tb ) return -1;
1624  if ( !ta ) return +1;
1625 
1626  if (ta->date_posted == tb->date_posted)
1627  return -1; // Keep the same order
1628  return (ta->date_posted > tb->date_posted) - (ta->date_posted < tb->date_posted);
1629 }
1630 
1631 static gboolean
1632 get_corr_account_split(const Split *sa, const Split **retval)
1633 {
1634  *retval = nullptr;
1635  g_return_val_if_fail(sa, FALSE);
1636 
1637  if (xaccTransCountSplits (sa->parent) > 2)
1638  return FALSE;
1639 
1640  *retval = xaccSplitGetOtherSplit (sa);
1641  if (*retval)
1642  return TRUE;
1643  else
1644  return FALSE;
1645 }
1646 
1647 /* TODO: these static consts can be shared. */
1648 const char *
1650 {
1651  static const char *split_const = nullptr;
1652  const Split *other_split;
1653 
1654  if (!get_corr_account_split(sa, &other_split))
1655  {
1656  if (!split_const)
1657  split_const = _("-- Split Transaction --");
1658 
1659  return split_const;
1660  }
1661 
1662  return xaccAccountGetName(other_split->acc);
1663 }
1664 
1665 char *
1667 {
1668  static const char *split_const = nullptr;
1669  const Split *other_split;
1670 
1671  if (!get_corr_account_split(sa, &other_split))
1672  {
1673  if (!split_const)
1674  split_const = _("-- Split Transaction --");
1675 
1676  return g_strdup(split_const);
1677  }
1678  return gnc_account_get_full_name(other_split->acc);
1679 }
1680 
1681 const char *
1683 {
1684  static const char *split_const = nullptr;
1685  const Split *other_split;
1686 
1687  if (!get_corr_account_split(sa, &other_split))
1688  {
1689  if (!split_const)
1690  split_const = C_("Displayed account code of the other account in a multi-split transaction", "Split");
1691 
1692  return split_const;
1693  }
1694  return xaccAccountGetCode(other_split->acc);
1695 }
1696 
1697 /* TODO: It's not too hard to make this function avoid the malloc/free. */
1698 int
1699 xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
1700 {
1701  Account *aa, *ab;
1702  if (sa == sb) return 0;
1703  if (!sa) return -1;
1704  if (!sb) return 1;
1705 
1706  aa = sa->acc;
1707  ab = sb->acc;
1708  if (aa == ab) return 0;
1709 
1710  auto path_a = gnc_account_get_all_parents (aa);
1711  auto path_b = gnc_account_get_all_parents (ab);
1712  auto mismatch_pair = std::mismatch (path_a.rbegin(), path_a.rend(),
1713  path_b.rbegin(), path_b.rend());
1714 
1715  return mismatch_pair.first == path_a.rend() ? -1
1716  : mismatch_pair.second == path_b.rend() ? 1
1717  : g_utf8_collate (xaccAccountGetName (*mismatch_pair.first),
1718  xaccAccountGetName (*mismatch_pair.second));
1719 }
1720 
1721 
1722 int
1723 xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
1724 {
1725  Account *aa, *ab;
1726  if (!sa && !sb) return 0;
1727  if (!sa) return -1;
1728  if (!sb) return 1;
1729 
1730  aa = sa->acc;
1731  ab = sb->acc;
1732 
1733  return g_strcmp0(xaccAccountGetCode(aa), xaccAccountGetCode(ab));
1734 }
1735 
1736 int
1737 xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
1738 {
1739  char *ca, *cb;
1740  int retval;
1741  if (!sa && !sb) return 0;
1742  if (!sa) return -1;
1743  if (!sb) return 1;
1744 
1745  /* doesn't matter what separator we use
1746  * as long as they are the same
1747  */
1748 
1751  retval = g_strcmp0(ca, cb);
1752  g_free(ca);
1753  g_free(cb);
1754  return retval;
1755 }
1756 
1757 int
1758 xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
1759 {
1760  const char *ca, *cb;
1761  if (!sa && !sb) return 0;
1762  if (!sa) return -1;
1763  if (!sb) return 1;
1764 
1765  ca = xaccSplitGetCorrAccountCode(sa);
1766  cb = xaccSplitGetCorrAccountCode(sb);
1767  return g_strcmp0(ca, cb);
1768 }
1769 
1770 static void
1771 qofSplitSetMemo (Split *split, const char* memo)
1772 {
1773  g_return_if_fail(split);
1774  CACHE_REPLACE(split->memo, memo);
1775 }
1776 
1777 void
1778 xaccSplitSetMemo (Split *split, const char *memo)
1779 {
1780  if (!split || !memo) return;
1781  xaccTransBeginEdit (split->parent);
1782 
1783  CACHE_REPLACE(split->memo, memo);
1784  qof_instance_set_dirty(QOF_INSTANCE(split));
1785  xaccTransCommitEdit(split->parent);
1786 
1787 }
1788 
1789 static void
1790 qofSplitSetAction (Split *split, const char *actn)
1791 {
1792  g_return_if_fail(split);
1793  CACHE_REPLACE(split->action, actn);
1794 }
1795 
1796 void
1797 xaccSplitSetAction (Split *split, const char *actn)
1798 {
1799  if (!split || !actn) return;
1800  xaccTransBeginEdit (split->parent);
1801 
1802  CACHE_REPLACE(split->action, actn);
1803  qof_instance_set_dirty(QOF_INSTANCE(split));
1804  xaccTransCommitEdit(split->parent);
1805 
1806 }
1807 
1808 static void
1809 qofSplitSetReconcile (Split *split, char recn)
1810 {
1811  g_return_if_fail(split);
1812  switch (recn)
1813  {
1814  case NREC:
1815  case CREC:
1816  case YREC:
1817  case FREC:
1818  case VREC:
1819  split->reconciled = recn;
1820  mark_split (split);
1821  xaccAccountRecomputeBalance (split->acc);
1822  break;
1823  default:
1824  PERR("Bad reconciled flag");
1825  break;
1826  }
1827 }
1828 
1829 void
1830 xaccSplitSetReconcile (Split *split, char recn)
1831 {
1832  if (!split || split->reconciled == recn) return;
1833  xaccTransBeginEdit (split->parent);
1834 
1835  switch (recn)
1836  {
1837  case NREC:
1838  case CREC:
1839  case YREC:
1840  case FREC:
1841  case VREC:
1842  split->reconciled = recn;
1843  mark_split (split);
1844  qof_instance_set_dirty(QOF_INSTANCE(split));
1845  xaccAccountRecomputeBalance (split->acc);
1846  break;
1847  default:
1848  PERR("Bad reconciled flag");
1849  break;
1850  }
1851  xaccTransCommitEdit(split->parent);
1852 
1853 }
1854 
1855 void
1857 {
1858  if (!split) return;
1859  xaccTransBeginEdit (split->parent);
1860 
1861  split->date_reconciled = secs;
1862  qof_instance_set_dirty(QOF_INSTANCE(split));
1863  xaccTransCommitEdit(split->parent);
1864 
1865 }
1866 
1867 
1868 /*################## Added for Reg2 #################*/
1869 time64
1870 xaccSplitGetDateReconciled (const Split * split)
1871 {
1872  return split ? split->date_reconciled : 0;
1873 }
1874 /*################## Added for Reg2 #################*/
1875 
1876 /********************************************************************\
1877 \********************************************************************/
1878 
1879 /* return the parent transaction of the split */
1880 Transaction *
1881 xaccSplitGetParent (const Split *split)
1882 {
1883  return split ? split->parent : nullptr;
1884 }
1885 
1886 void
1887 xaccSplitSetParent(Split *s, Transaction *t)
1888 {
1889  Transaction *old_trans;
1890  GncEventData ed;
1891 
1892  g_return_if_fail(s);
1893  if (s->parent == t) return;
1894 
1895  if (s->parent != s->orig_parent && s->orig_parent != t)
1896  PERR("You may not add the split to more than one transaction"
1897  " during the BeginEdit/CommitEdit block.");
1898  xaccTransBeginEdit(t);
1899  old_trans = s->parent;
1900 
1901  xaccTransBeginEdit(old_trans);
1902 
1903  ed.node = s;
1904  if (old_trans)
1905  {
1906  ed.idx = xaccTransGetSplitIndex(old_trans, s);
1907  qof_event_gen(&old_trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1908  }
1909  s->parent = t;
1910  qof_instance_set_dirty(QOF_INSTANCE(s));
1911 
1912  xaccTransCommitEdit(old_trans);
1913 
1914  if (t)
1915  {
1916  /* Convert split to new transaction's commodity denominator */
1918 
1919  /* add ourselves to the new transaction's list of pending splits. */
1920  if (nullptr == g_list_find(t->splits, s))
1921  t->splits = g_list_append(t->splits, s);
1922 
1923  ed.idx = -1; /* unused */
1924  qof_event_gen(&t->inst, GNC_EVENT_ITEM_ADDED, &ed);
1925  }
1927 }
1928 
1929 
1930 GNCLot *
1931 xaccSplitGetLot (const Split *split)
1932 {
1933  return split ? split->lot : nullptr;
1934 }
1935 
1936 void
1937 xaccSplitSetLot(Split* split, GNCLot* lot)
1938 {
1939  xaccTransBeginEdit (split->parent);
1940  split->lot = lot;
1941  qof_instance_set_dirty(QOF_INSTANCE(split));
1942  xaccTransCommitEdit(split->parent);
1943 }
1944 
1945 const char *
1946 xaccSplitGetMemo (const Split *split)
1947 {
1948  return split ? split->memo : nullptr;
1949 }
1950 
1951 void
1952 xaccSplitSetOnlineID (Split *split, const char *id)
1953 {
1954  if (!split) return;
1955  /* No xaccTransBeginEdit/CommitEdit here: the online_id is normally set
1956  * while many other parameters of a transaction are being changed, so
1957  * the caller wraps this in the parent transaction's edit. */
1958  std::optional<const char*> val;
1959  if (id && *id)
1960  val = g_strdup (id);
1961  qof_instance_set_path_kvp<const char*> (QOF_INSTANCE(split), val, {split_online_id});
1962  qof_instance_set_dirty (QOF_INSTANCE(split));
1963 }
1964 
1965 const char *
1966 xaccSplitGetOnlineID (const Split *split)
1967 {
1968  if (!split) return nullptr;
1969  auto rv{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(split), {split_online_id})};
1970  return rv ? *rv : nullptr;
1971 }
1972 
1973 gboolean
1974 xaccSplitHasOnlineID (const Split *split)
1975 {
1976  auto id = xaccSplitGetOnlineID (split);
1977  return (id && *id);
1978 }
1979 
1980 const char *
1981 xaccSplitGetAction (const Split *split)
1982 {
1983  return split ? split->action : nullptr;
1984 }
1985 
1986 char
1987 xaccSplitGetReconcile (const Split *split)
1988 {
1989  return split ? split->reconciled : ' ';
1990 }
1991 
1992 
1993 gnc_numeric
1994 xaccSplitGetAmount (const Split * split)
1995 {
1996  return split ? split->amount : gnc_numeric_zero();
1997 }
1998 
1999 gnc_numeric
2000 xaccSplitGetValue (const Split * split)
2001 {
2002  return split ? split->value : gnc_numeric_zero();
2003 }
2004 
2005 gnc_numeric
2006 xaccSplitGetSharePrice (const Split * split)
2007 {
2008  gnc_numeric amt, val, price;
2009  if (!split) return gnc_numeric_create(0, 1);
2010 
2011 
2012  /* if amount == 0, return 0
2013  * otherwise return value/amount
2014  */
2015 
2016  amt = xaccSplitGetAmount(split);
2017  val = xaccSplitGetValue(split);
2018  if (gnc_numeric_zero_p(amt))
2019  return gnc_numeric_create(0, 1);
2020 
2021  price = gnc_numeric_div(val, amt,
2024 
2025  /* During random checks we can get some very weird prices. Let's
2026  * handle some overflow and other error conditions by returning
2027  * zero. But still print an error to let us know it happened.
2028  */
2029  if (gnc_numeric_check(price))
2030  {
2031  PERR("Computing share price failed (%d): [ %" G_GINT64_FORMAT " / %"
2032  G_GINT64_FORMAT " ] / [ %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " ]",
2033  gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
2034  return gnc_numeric_create(0, 1);
2035  }
2036 
2037  return price;
2038 }
2039 
2040 /********************************************************************\
2041 \********************************************************************/
2042 
2043 QofBook *
2044 xaccSplitGetBook (const Split *split)
2045 {
2046  return qof_instance_get_book(QOF_INSTANCE(split));
2047 }
2048 
2049 const char *
2051 {
2052  if (!s) return nullptr;
2053 
2054  if (!s->split_type)
2055  {
2056  auto type{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(s), {"split-type"})};
2057 
2058  if (!type || !g_strcmp0 (*type, split_type_normal))
2059  s->split_type = split_type_normal;
2060  else if (!g_strcmp0 (*type, split_type_stock_split))
2061  s->split_type = split_type_stock_split;
2062  else
2063  {
2064  PERR ("unexpected split-type %s, reset to normal.", *type);
2065  s->split_type = split_type_normal;
2066  }
2067  }
2068  return s->split_type;
2069 }
2070 
2071 /* reconfigure a split to be a stock split - after this, you shouldn't
2072  mess with the value, just the amount. */
2073 void
2075 {
2076  xaccTransBeginEdit (s->parent);
2077 
2078  s->value = gnc_numeric_zero();
2079  s->split_type = split_type_stock_split;
2080  qof_instance_set_path_kvp<const char*> (QOF_INSTANCE(s), g_strdup(split_type_stock_split),
2081  {"split-type"});
2082  SET_GAINS_VDIRTY(s);
2083  mark_split(s);
2084  qof_instance_set_dirty(QOF_INSTANCE(s));
2085  xaccTransCommitEdit(s->parent);
2086 }
2087 
2088 gboolean
2090 {
2091  return g_strcmp0(split_type_stock_split, xaccSplitGetType(s)) == 0;
2092 }
2093 
2094 void
2095 xaccSplitAddPeerSplit (Split *split, const Split *other_split,
2096  time64 timestamp)
2097 {
2098  const GncGUID* guid;
2099 
2100  g_return_if_fail (split != nullptr);
2101  g_return_if_fail (other_split != nullptr);
2102 
2103  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2104  xaccTransBeginEdit (split->parent);
2105  qof_instance_kvp_add_guid (QOF_INSTANCE (split), "lot-split",
2106  gnc_time(nullptr), "peer_guid", guid_copy(guid));
2107  mark_split (split);
2108  qof_instance_set_dirty (QOF_INSTANCE (split));
2109  xaccTransCommitEdit (split->parent);
2110 }
2111 
2112 gboolean
2113 xaccSplitHasPeers (const Split *split)
2114 {
2115  return qof_instance_has_slot (QOF_INSTANCE (split), "lot-split");
2116 }
2117 
2118 gboolean
2119 xaccSplitIsPeerSplit (const Split *split, const Split *other_split)
2120 {
2121  const GncGUID* guid;
2122 
2123  g_return_val_if_fail (split != nullptr, FALSE);
2124  g_return_val_if_fail (other_split != nullptr, FALSE);
2125 
2126  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2127  return qof_instance_kvp_has_guid (QOF_INSTANCE (split), "lot-split",
2128  "peer_guid", guid);
2129 }
2130 
2131 void
2132 xaccSplitRemovePeerSplit (Split *split, const Split *other_split)
2133 {
2134  const GncGUID* guid;
2135 
2136  g_return_if_fail (split != nullptr);
2137  g_return_if_fail (other_split != nullptr);
2138 
2139  guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2140  xaccTransBeginEdit (split->parent);
2141  qof_instance_kvp_remove_guid (QOF_INSTANCE (split), "lot-split",
2142  "peer_guid", guid);
2143  mark_split (split);
2144  qof_instance_set_dirty (QOF_INSTANCE (split));
2145  xaccTransCommitEdit (split->parent);
2146 }
2147 
2148 void
2149 xaccSplitMergePeerSplits (Split *split, const Split *other_split)
2150 {
2151  xaccTransBeginEdit (split->parent);
2152  qof_instance_kvp_merge_guids (QOF_INSTANCE (split),
2153  QOF_INSTANCE (other_split), "lot-split");
2154  mark_split (split);
2155  qof_instance_set_dirty (QOF_INSTANCE (split));
2156  xaccTransCommitEdit (split->parent);
2157 }
2158 
2159 /********************************************************************\
2160 \********************************************************************/
2161 /* In the old world, the 'other split' was the other split of a
2162  * transaction that contained only two splits. In the new world,
2163  * a split may have been cut up between multiple lots, although
2164  * in a conceptual sense, if lots hadn't been used, there would be
2165  * only a pair. So we handle this conceptual case: we can still
2166  * identify, unambiguously, the 'other' split when 'this' split
2167  * as been cut up across lots. We do this by looking for the
2168  * 'lot-split' keyword, which occurs only in cut-up splits.
2169  */
2170 
2171 Split *
2172 xaccSplitGetOtherSplit (const Split *split)
2173 {
2174  Transaction *trans;
2175  Split *other = nullptr;
2176 
2177  if (!split) return nullptr;
2178  trans = split->parent;
2179  if (!trans) return nullptr;
2180 
2181  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
2182  {
2183  Split *s = GNC_SPLIT(n->data);
2184  if ((s == split) ||
2185  (!xaccTransStillHasSplit(trans, s)) ||
2187  (qof_instance_has_slot (QOF_INSTANCE (s), "lot-split")))
2188  continue;
2189 
2190  if (other)
2191  return nullptr;
2192 
2193  other = s;
2194  }
2195  return other;
2196 }
2197 
2198 /********************************************************************\
2199 \********************************************************************/
2200 
2201 gnc_numeric
2202 xaccSplitVoidFormerAmount(const Split *split)
2203 {
2204  g_return_val_if_fail(split, gnc_numeric_zero());
2205  auto num{qof_instance_get_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {void_former_amt_str})};
2206  return num ? *num : gnc_numeric_zero();
2207 }
2208 
2209 gnc_numeric
2210 xaccSplitVoidFormerValue(const Split *split)
2211 {
2212  g_return_val_if_fail(split, gnc_numeric_zero());
2213  auto num{qof_instance_get_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {void_former_val_str})};
2214  return num ? *num : gnc_numeric_zero();
2215 }
2216 
2217 void
2218 xaccSplitVoid(Split *split)
2219 {
2220  g_return_if_fail (GNC_IS_SPLIT(split));
2221  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), xaccSplitGetAmount(split), {void_former_amt_str});
2222  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), xaccSplitGetValue(split), {void_former_val_str});
2223  qof_instance_set_dirty (QOF_INSTANCE(split));
2224 
2225  static gnc_numeric zero = gnc_numeric_zero();
2226  xaccSplitSetAmount (split, zero);
2227  xaccSplitSetValue (split, zero);
2228  xaccSplitSetReconcile(split, VREC);
2229 }
2230 
2231 void
2232 xaccSplitUnvoid(Split *split)
2233 {
2234  g_return_if_fail (GNC_IS_SPLIT(split));
2237  xaccSplitSetReconcile(split, NREC);
2238  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {}, {void_former_amt_str});
2239  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {}, {void_former_val_str});
2240  qof_instance_set_dirty (QOF_INSTANCE(split));
2241 }
2242 
2243 /********************************************************************\
2244 \********************************************************************/
2245 /* QofObject function implementation */
2246 
2247 /* Hook into the QofObject registry */
2248 
2249 #ifdef _MSC_VER
2250 /* MSVC compiler doesn't have C99 "designated initializers"
2251  * so we wrap them in a macro that is empty on MSVC. */
2252 # define DI(x) /* */
2253 #else
2254 # define DI(x) x
2255 #endif
2256 static QofObject split_object_def =
2257 {
2258  DI(.interface_version = ) QOF_OBJECT_VERSION,
2259  DI(.e_type = ) GNC_ID_SPLIT,
2260  DI(.type_label = ) "Split",
2261  DI(.create = ) (void* (*)(QofBook*))xaccMallocSplit,
2262  DI(.book_begin = ) nullptr,
2263  DI(.book_end = ) nullptr,
2264  DI(.is_dirty = ) qof_collection_is_dirty,
2265  DI(.mark_clean = ) qof_collection_mark_clean,
2266  DI(.foreach = ) qof_collection_foreach,
2267  DI(.printable = ) (const char * (*)(gpointer)) xaccSplitGetMemo,
2268  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
2269 };
2270 
2271 static gpointer
2272 split_account_guid_getter (gpointer obj, const QofParam *p)
2273 {
2274  Split *s = GNC_SPLIT(obj);
2275  Account *acc;
2276 
2277  if (!s) return nullptr;
2278  acc = xaccSplitGetAccount (s);
2279  if (!acc) return nullptr;
2280  return ((gpointer)xaccAccountGetGUID (acc));
2281 }
2282 
2283 static double /* internal use only */
2284 DxaccSplitGetShareAmount (const Split * split)
2285 {
2286  return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
2287 }
2288 
2289 static gpointer
2290 no_op (gpointer obj, const QofParam *p)
2291 {
2292  return obj;
2293 }
2294 
2295 static void
2296 qofSplitSetParentTrans(Split *s, QofInstance *ent)
2297 {
2298  Transaction *trans = (Transaction*)ent;
2299 
2300  g_return_if_fail(trans);
2301  xaccSplitSetParent(s, trans);
2302 }
2303 
2304 static void
2305 qofSplitSetAccount(Split *s, QofInstance *ent)
2306 {
2307  Account *acc = (Account*)ent;
2308 
2309  g_return_if_fail(acc);
2310  xaccSplitSetAccount(s, acc);
2311 }
2312 
2313 gboolean xaccSplitRegister (void)
2314 {
2315  static const QofParam params[] =
2316  {
2317  {
2318  SPLIT_DATE_RECONCILED, QOF_TYPE_DATE,
2321  },
2322 
2323  /* d-* are deprecated query params, should not be used in new
2324  * queries, should be removed from old queries. */
2325  {
2326  "d-share-amount", QOF_TYPE_DOUBLE,
2327  (QofAccessFunc)DxaccSplitGetShareAmount, nullptr
2328  },
2329  {
2330  "d-share-int64", QOF_TYPE_INT64,
2332  },
2333  {
2334  SPLIT_BALANCE, QOF_TYPE_NUMERIC,
2336  },
2337  {
2338  SPLIT_CLEARED_BALANCE, QOF_TYPE_NUMERIC,
2340  },
2341  {
2342  SPLIT_RECONCILED_BALANCE, QOF_TYPE_NUMERIC,
2344  },
2345  {
2346  SPLIT_MEMO, QOF_TYPE_STRING,
2347  (QofAccessFunc)xaccSplitGetMemo, (QofSetterFunc)qofSplitSetMemo
2348  },
2349  {
2350  SPLIT_ACTION, QOF_TYPE_STRING,
2351  (QofAccessFunc)xaccSplitGetAction, (QofSetterFunc)qofSplitSetAction
2352  },
2353  {
2354  SPLIT_RECONCILE, QOF_TYPE_CHAR,
2356  (QofSetterFunc)qofSplitSetReconcile
2357  },
2358  {
2359  SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
2360  (QofAccessFunc)xaccSplitGetAmount, (QofSetterFunc)qofSplitSetAmount
2361  },
2362  {
2363  SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
2365  (QofSetterFunc)qofSplitSetSharePrice
2366  },
2367  {
2368  SPLIT_VALUE, QOF_TYPE_DEBCRED,
2369  (QofAccessFunc)xaccSplitGetValue, (QofSetterFunc)qofSplitSetValue
2370  },
2371  { SPLIT_TYPE, QOF_TYPE_STRING, (QofAccessFunc)xaccSplitGetType, nullptr },
2372  {
2373  SPLIT_VOIDED_AMOUNT, QOF_TYPE_NUMERIC,
2375  },
2376  {
2377  SPLIT_VOIDED_VALUE, QOF_TYPE_NUMERIC,
2379  },
2380  { SPLIT_LOT, GNC_ID_LOT, (QofAccessFunc)xaccSplitGetLot, nullptr },
2381  {
2382  SPLIT_TRANS, GNC_ID_TRANS,
2384  (QofSetterFunc)qofSplitSetParentTrans
2385  },
2386  {
2387  SPLIT_ACCOUNT, GNC_ID_ACCOUNT,
2388  (QofAccessFunc)xaccSplitGetAccount, (QofSetterFunc)qofSplitSetAccount
2389  },
2390  { SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, nullptr },
2391  /* these are no-ops to register the parameter names (for sorting) but
2392  they return an allocated object which getters cannot do. */
2393  { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, nullptr },
2394  { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, nullptr },
2395  { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, nullptr },
2396  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, nullptr },
2397  {
2398  QOF_PARAM_GUID, QOF_TYPE_GUID,
2400  },
2401  { nullptr },
2402  };
2403 
2404  qof_class_register (GNC_ID_SPLIT, (QofSortFunc)xaccSplitOrder, params);
2405  qof_class_register (SPLIT_ACCT_FULLNAME,
2407  qof_class_register (SPLIT_CORR_ACCT_NAME,
2409  nullptr);
2410  qof_class_register (SPLIT_CORR_ACCT_CODE,
2412 
2413  return qof_object_register (&split_object_def);
2414 }
2415 
2417 _utest_split_fill_functions (void)
2418 {
2419  SplitTestFunctions *func = g_new (SplitTestFunctions, 1);
2420 
2421  func->xaccSplitEqualCheckBal = xaccSplitEqualCheckBal;
2422  func->get_currency_denom = get_currency_denom;
2423  func->get_commodity_denom = get_commodity_denom;
2424  func->get_corr_account_split = get_corr_account_split;
2425  return func;
2426 }
2427 
2428 /************************ END OF ************************************\
2429 \************************* 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:1291
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:1339
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition: Split.cpp:1547
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:1357
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:2095
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:1366
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition: Split.cpp:1797
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:2074
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:1723
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:1345
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3255
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1517
gboolean xaccSplitHasOnlineID(const Split *split)
Returns TRUE if the split has a non-empty online_id.
Definition: Split.cpp:1974
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:2733
const char * xaccAccountGetCode(const Account *acc)
Get the account&#39;s accounting code.
Definition: Account.cpp:3324
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:1987
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:1961
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
Definition: cap-gains.cpp:514
Object instance holds common fields that most gnucash objects use.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Definition: Split.cpp:1830
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2128
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition: Split.cpp:1881
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:2132
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:2050
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:169
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:1737
#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:2044
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:1966
#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:1327
#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:131
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:1699
#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:2113
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:2149
gnc_numeric xaccSplitVoidFormerAmount(const Split *split)
Returns the original pre-void amount of a split.
Definition: Split.cpp:2202
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:1254
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:3293
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:2210
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:1778
#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:1758
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:1188
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:1333
#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:2263
gboolean xaccSplitIsPeerSplit(const Split *split, const Split *other_split)
Report if a split is a peer of this one.
Definition: Split.cpp:2119
char * xaccSplitGetCorrAccountFullName(const Split *sa)
These functions take a split, get the corresponding split on the "other side" of the transaction...
Definition: Split.cpp:1666
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:124
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
Definition: Split.cpp:2089
#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:2006
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:1421
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: Split.cpp:539
const char * xaccSplitGetCorrAccountName(const Split *sa)
document me
Definition: Split.cpp:1649
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:1931
void xaccSplitSetLot(Split *split, GNCLot *lot)
Assigns the split to a specific Lot.
Definition: Split.cpp:1937
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:1856
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition: Split.cpp:1870
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: Split.cpp:2000
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:3396
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:1952
const char * xaccSplitGetCorrAccountCode(const Split *sa)
document me
Definition: Split.cpp:1682
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
Definition: Split.cpp:2172
#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:1216
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:1946
const char * xaccSplitGetAction(const Split *split)
Returns the action string.
Definition: Split.cpp:1981
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:3277
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:1351
#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:1931
#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:1994