GnuCash c935c2f+
Loading...
Searching...
No Matches
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
62const char *void_former_amt_str = "void-former-amount";
63const char *void_former_val_str = "void-former-value";
64
65/* This static indicates the debugging module that this .o belongs to. */
66static 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
77enum
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
102static const char * split_type_normal = "normal";
103static const char * split_type_stock_split = "stock-split";
104static const char * split_online_id = "online_id";
105
106/* GObject Initialization */
107G_DEFINE_TYPE(Split, gnc_split, QOF_TYPE_INSTANCE)
108
109static void
110gnc_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
138static void
139gnc_split_dispose(GObject *splitp)
140{
141 G_OBJECT_CLASS(gnc_split_parent_class)->dispose(splitp);
142}
143
144static void
145gnc_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 */
155static void
156gnc_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
227static void
228gnc_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));
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
304static void
305gnc_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
498static void
499xaccInitSplit(Split * split, QofBook *book)
500{
501 qof_instance_init_data(&split->inst, GNC_ID_SPLIT, book);
502}
503
504void
505xaccSplitReinit(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
538Split *
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
559Split *
560xaccDupeSplit (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
597Split *
598xaccSplitCloneNoKvp (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
630void
631xaccSplitCopyKvp (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*/
647void
648xaccSplitCopyOnto(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
671void
672xaccSplitDump (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\********************************************************************/
708static void
709do_destroy (QofInstance *inst)
710{
711 xaccFreeSplit (GNC_SPLIT (inst));
712}
713
714void
715xaccFreeSplit (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
783void 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 */
796static gboolean
797xaccSplitEqualCheckBal (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 ********************************************************************/
818gboolean
819xaccSplitEqual(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
955Account *
956xaccSplitGetAccount (const Split *s)
957{
958 return s ? s->acc : nullptr;
959}
960
961void
962xaccSplitSetAccount (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
980static 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(). */
987void
988xaccSplitCommitEdit(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(). */
1062void
1063xaccSplitRollbackEdit(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
1090Split *
1091xaccSplitLookup (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? */
1109void
1110xaccSplitDetermineGainStatus (Split *split)
1111{
1112 Split *other;
1113 GncGUID *guid = nullptr;
1114
1115 if (GAINS_STATUS_UNKNOWN != split->gains) return;
1116
1117 other = xaccSplitGetCapGainsSplit (split);
1118 if (other)
1119 {
1120 split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1121 split->gains_split = other;
1122 return;
1123 }
1124
1125 if (auto v = qof_instance_get_path_kvp<GncGUID*> (QOF_INSTANCE (split), {"gains-source"}))
1126 guid = const_cast<GncGUID*>(*v);
1127
1128 if (!guid)
1129 {
1130 // CHECKME: We leave split->gains_split alone. Is that correct?
1131 split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
1132 }
1133 else
1134 {
1135 QofCollection *col;
1137 GNC_ID_SPLIT);
1138 split->gains = GAINS_STATUS_GAINS;
1139 other = (Split *) qof_collection_lookup_entity (col, guid);
1140 split->gains_split = other;
1141 }
1142}
1143
1144/********************************************************************\
1145\********************************************************************/
1146
1147static inline int
1148get_currency_denom(const Split * s)
1149{
1150 if (!(s && s->parent && s->parent->common_currency))
1151 {
1152 return GNC_DENOM_AUTO;
1153 }
1154 else
1155 {
1156 return gnc_commodity_get_fraction (s->parent->common_currency);
1157 }
1158}
1159
1160static inline int
1161get_commodity_denom(const Split * s)
1162{
1163 if (!(s && s->acc))
1164 {
1165 return GNC_DENOM_AUTO;
1166 }
1167 else
1168 {
1169 return xaccAccountGetCommoditySCU(s->acc);
1170 }
1171}
1172
1173/********************************************************************\
1174\********************************************************************/
1175
1176void
1177xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)
1178{
1179 if (!s) return;
1180 ENTER (" ");
1181 xaccTransBeginEdit (s->parent);
1182
1183 s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1185 s->value = gnc_numeric_mul(s->amount, price,
1186 get_currency_denom(s), GNC_HOW_RND_ROUND_HALF_UP);
1187
1188 SET_GAINS_A_VDIRTY(s);
1189 mark_split (s);
1190 qof_instance_set_dirty(QOF_INSTANCE(s));
1191 xaccTransCommitEdit(s->parent);
1192 LEAVE ("");
1193}
1194
1195static void
1196qofSplitSetSharePrice (Split *split, gnc_numeric price)
1197{
1198 g_return_if_fail(split);
1199 split->value = gnc_numeric_mul(xaccSplitGetAmount(split),
1200 price, get_currency_denom(split),
1201 GNC_HOW_RND_ROUND_HALF_UP);
1202}
1203
1204void
1205xaccSplitSetSharePrice (Split *s, gnc_numeric price)
1206{
1207 if (!s) return;
1208
1209 if (gnc_numeric_zero_p (price))
1210 return;
1211
1212 ENTER (" ");
1213 xaccTransBeginEdit (s->parent);
1214
1215 s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
1216 price, get_currency_denom(s),
1218
1219 SET_GAINS_VDIRTY(s);
1220 mark_split (s);
1221 qof_instance_set_dirty(QOF_INSTANCE(s));
1222 xaccTransCommitEdit(s->parent);
1223 LEAVE ("");
1224}
1225
1226static void
1227qofSplitSetAmount (Split *split, gnc_numeric amt)
1228{
1229 g_return_if_fail(split);
1230 if (split->acc)
1231 {
1232 split->amount = gnc_numeric_convert(amt,
1233 get_commodity_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1234 }
1235 else
1236 {
1237 split->amount = amt;
1238 }
1239}
1240
1241/* The amount of the split in the _account's_ commodity. */
1242void
1243xaccSplitSetAmount (Split *s, gnc_numeric amt)
1244{
1245 if (!s) return;
1246 g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1247 ENTER ("(split=%p) old amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1248 " new amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1249 s->amount.num, s->amount.denom, amt.num, amt.denom);
1250
1251 xaccTransBeginEdit (s->parent);
1252 if (s->acc)
1253 {
1254 s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1256 g_assert (gnc_numeric_check (s->amount) == GNC_ERROR_OK);
1257 }
1258 else
1259 s->amount = amt;
1260 s->adjusted_amount = s->amount;
1261
1262 SET_GAINS_ADIRTY(s);
1263 mark_split (s);
1264 qof_instance_set_dirty(QOF_INSTANCE(s));
1265 xaccTransCommitEdit(s->parent);
1266 LEAVE("");
1267}
1268
1269static void
1270qofSplitSetValue (Split *split, gnc_numeric amt)
1271{
1272 g_return_if_fail(split);
1273 split->value = gnc_numeric_convert(amt,
1274 get_currency_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1275 g_assert(gnc_numeric_check (split->value) != GNC_ERROR_OK);
1276}
1277
1278/* The value of the split in the _transaction's_ currency. */
1279void
1280xaccSplitSetValue (Split *s, gnc_numeric amt)
1281{
1282 gnc_numeric new_val;
1283 if (!s) return;
1284
1285 g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1286 ENTER ("(split=%p) old val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1287 " new val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1288 s->value.num, s->value.denom, amt.num, amt.denom);
1289
1290 xaccTransBeginEdit (s->parent);
1291 new_val = gnc_numeric_convert(amt, get_currency_denom(s),
1293 if (gnc_numeric_check(new_val) == GNC_ERROR_OK &&
1294 !(gnc_numeric_zero_p (new_val) && !gnc_numeric_zero_p (amt)))
1295 {
1296 s->value = new_val;
1297 }
1298 else
1299 {
1300 PERR("numeric error %s in converting the split value's denominator with amount %s and denom %d",
1302 gnc_num_dbg_to_string (amt), get_currency_denom(s));
1303 }
1304
1305 SET_GAINS_VDIRTY(s);
1306 mark_split (s);
1307 qof_instance_set_dirty(QOF_INSTANCE(s));
1308 xaccTransCommitEdit(s->parent);
1309 LEAVE ("");
1310}
1311
1312/********************************************************************\
1313\********************************************************************/
1314
1315gnc_numeric
1316xaccSplitGetBalance (const Split *s)
1317{
1318 return s ? s->balance : gnc_numeric_zero();
1319}
1320
1321gnc_numeric
1323{
1324 return s ? s->noclosing_balance : gnc_numeric_zero();
1325}
1326
1327gnc_numeric
1329{
1330 return s ? s->cleared_balance : gnc_numeric_zero();
1331}
1332
1333gnc_numeric
1335{
1336 return s ? s->reconciled_balance : gnc_numeric_zero();
1337}
1338
1339gnc_numeric
1341{
1342 return s ? s->adjusted_amount : gnc_numeric_zero();
1343}
1344
1345void
1346xaccSplitSetAdjustedAmount (Split *s, gnc_numeric amt)
1347{
1348 if (!s) return;
1349 if (gnc_numeric_check (amt)) return;
1350
1351 s->adjusted_amount = amt;
1352}
1353
1354void
1355xaccSplitSetBaseValue (Split *s, gnc_numeric value,
1356 const gnc_commodity * base_currency)
1357{
1358 const gnc_commodity *currency;
1359 const gnc_commodity *commodity;
1360
1361 if (!s) return;
1362 xaccTransBeginEdit (s->parent);
1363
1364 if (!s->acc)
1365 {
1366 PERR ("split must have a parent account");
1367 return;
1368 }
1369
1370 currency = xaccTransGetCurrency (s->parent);
1371 commodity = xaccAccountGetCommodity (s->acc);
1372
1373 /* If the base_currency is the transaction's commodity ('currency'),
1374 * set the value. If it's the account commodity, set the
1375 * amount. If both, set both. */
1376 if (gnc_commodity_equiv(currency, base_currency))
1377 {
1378 if (gnc_commodity_equiv(commodity, base_currency))
1379 {
1380 s->amount = gnc_numeric_convert(value,
1381 get_commodity_denom(s),
1383 }
1384 s->value = gnc_numeric_convert(value,
1385 get_currency_denom(s),
1387 }
1388 else if (gnc_commodity_equiv(commodity, base_currency))
1389 {
1390 s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
1392 }
1393 else
1394 {
1395 PERR ("inappropriate base currency %s "
1396 "given split currency=%s and commodity=%s\n",
1397 gnc_commodity_get_printname(base_currency),
1399 gnc_commodity_get_printname(commodity));
1400 return;
1401 }
1402
1403 SET_GAINS_A_VDIRTY(s);
1404 mark_split (s);
1405 qof_instance_set_dirty(QOF_INSTANCE(s));
1406 xaccTransCommitEdit(s->parent);
1407}
1408
1409gnc_numeric
1410xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)
1411{
1412 if (!s || !s->acc || !s->parent) return gnc_numeric_zero();
1413
1414 /* be more precise -- the value depends on the currency we want it
1415 * expressed in. */
1416 if (gnc_commodity_equiv(xaccTransGetCurrency(s->parent), base_currency))
1417 return xaccSplitGetValue(s);
1418 if (gnc_commodity_equiv(xaccAccountGetCommodity(s->acc), base_currency))
1419 return xaccSplitGetAmount(s);
1420
1421 PERR ("inappropriate base currency %s "
1422 "given split currency=%s and commodity=%s\n",
1423 gnc_commodity_get_printname(base_currency),
1426 return gnc_numeric_zero();
1427}
1428
1429/********************************************************************\
1430\********************************************************************/
1431
1432gnc_numeric
1433xaccSplitConvertAmount (const Split *split, const Account * account)
1434{
1435 gnc_commodity *acc_com, *to_commodity;
1436 Transaction *txn;
1437 gnc_numeric amount, value, convrate;
1438 Account * split_acc;
1439
1440 amount = xaccSplitGetAmount (split);
1441
1442 /* If this split is attached to this account, OR */
1443 split_acc = xaccSplitGetAccount (split);
1444 if (split_acc == account)
1445 return amount;
1446
1447 /* If split->account->commodity == to_commodity, return the amount */
1448 acc_com = xaccAccountGetCommodity (split_acc);
1449 to_commodity = xaccAccountGetCommodity (account);
1450 if (acc_com && gnc_commodity_equal (acc_com, to_commodity))
1451 return amount;
1452
1453 /* Ok, this split is not for the viewed account, and the commodity
1454 * does not match. So we need to do some conversion.
1455 *
1456 * First, we can cheat. If this transaction is balanced and has
1457 * exactly two splits, then we can implicitly determine the exchange
1458 * rate and just return the 'other' split amount.
1459 */
1460 txn = xaccSplitGetParent (split);
1461 if (txn && xaccTransIsBalanced (txn))
1462 {
1463 const Split *osplit = xaccSplitGetOtherSplit (split);
1464
1465 if (osplit)
1466 {
1467 gnc_commodity* split_comm =
1469 if (!gnc_commodity_equal(to_commodity, split_comm))
1470 {
1471 gchar guidstr[GUID_ENCODING_LENGTH+1];
1472 guid_to_string_buff(xaccSplitGetGUID(osplit),guidstr);
1473 PERR("The split's (%s) amount can't be converted from %s into %s.",
1474 guidstr,
1475 gnc_commodity_get_mnemonic(split_comm),
1476 gnc_commodity_get_mnemonic(to_commodity)
1477 );
1478 return gnc_numeric_zero();
1479 }
1480 return gnc_numeric_neg (xaccSplitGetAmount (osplit));
1481 }
1482 }
1483
1484 /* ... otherwise, we need to compute the amount from the conversion
1485 * rate into _this account_. So, find the split into this account,
1486 * compute the conversion rate (based on amount/value), and then multiply
1487 * this times the split value.
1488 */
1489 value = xaccSplitGetValue (split);
1490
1491 if (gnc_numeric_zero_p (value))
1492 {
1493 return value;
1494 }
1495
1496 convrate = xaccTransGetAccountConvRate(txn, account);
1497 return gnc_numeric_mul (value, convrate,
1498 gnc_commodity_get_fraction (to_commodity),
1499 GNC_HOW_RND_ROUND_HALF_UP);
1500}
1501
1502/********************************************************************\
1503\********************************************************************/
1504
1505gboolean
1506xaccSplitDestroy (Split *split)
1507{
1508 Account *acc;
1509 Transaction *trans;
1510 GncEventData ed;
1511
1512 if (!split) return TRUE;
1513
1514 acc = split->acc;
1515 trans = split->parent;
1516 if (acc && !qof_instance_get_destroying(acc)
1518 && xaccTransGetReadOnly(trans))
1519 return FALSE;
1520
1521 xaccTransBeginEdit(trans);
1522 ed.node = split;
1523 ed.idx = xaccTransGetSplitIndex(trans, split);
1524 qof_instance_set_dirty(QOF_INSTANCE(split));
1525 qof_instance_set_destroying(split, TRUE);
1526 qof_event_gen(&trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1527 xaccTransCommitEdit(trans);
1528
1529 return TRUE;
1530}
1531
1532/********************************************************************\
1533\********************************************************************/
1534
1535gint
1536xaccSplitOrder (const Split *sa, const Split *sb)
1537{
1538 int retval;
1539 int comp;
1540 const char *da, *db;
1541 gboolean action_for_num;
1542
1543 if (sa == sb) return 0;
1544 /* nothing is always less than something */
1545 if (!sa) return -1;
1546 if (!sb) return +1;
1547
1548 /* sort in transaction order, but use split action rather than trans num
1549 * according to book option */
1551 (xaccSplitGetBook (sa));
1552 if (action_for_num)
1553 retval = xaccTransOrder_num_action (sa->parent, sa->action,
1554 sb->parent, sb->action);
1555 else
1556 retval = xaccTransOrder (sa->parent, sb->parent);
1557 if (retval) return retval;
1558
1559 /* otherwise, sort on memo strings */
1560 da = sa->memo ? sa->memo : "";
1561 db = sb->memo ? sb->memo : "";
1562 retval = g_utf8_collate (da, db);
1563 if (retval)
1564 return retval;
1565
1566 /* otherwise, sort on action strings */
1567 da = sa->action ? sa->action : "";
1568 db = sb->action ? sb->action : "";
1569 retval = g_utf8_collate (da, db);
1570 if (retval != 0)
1571 return retval;
1572
1573 /* the reconciled flag ... */
1574 if (sa->reconciled < sb->reconciled) return -1;
1575 if (sa->reconciled > sb->reconciled) return +1;
1576
1577 /* compare amounts */
1579 if (comp < 0) return -1;
1580 if (comp > 0) return +1;
1581
1583 if (comp < 0) return -1;
1584 if (comp > 0) return +1;
1585
1586 /* if dates differ, return */
1587 if (sa->date_reconciled < sb->date_reconciled)
1588 return -1;
1589 else if (sa->date_reconciled > sb->date_reconciled)
1590 return 1;
1591
1592 /* else, sort on guid - keeps sort stable. */
1593 retval = qof_instance_guid_compare(sa, sb);
1594 if (retval) return retval;
1595
1596 return 0;
1597}
1598
1599gint
1600xaccSplitOrderDateOnly (const Split *sa, const Split *sb)
1601{
1602 Transaction *ta, *tb;
1603
1604 if (sa == sb) return 0;
1605 /* nothing is always less than something */
1606 if (!sa) return -1;
1607 if (!sb) return +1;
1608
1609 ta = sa->parent;
1610 tb = sb->parent;
1611 if ( !ta && !tb ) return 0;
1612 if ( !tb ) return -1;
1613 if ( !ta ) return +1;
1614
1615 if (ta->date_posted == tb->date_posted)
1616 return -1; // Keep the same order
1617 return (ta->date_posted > tb->date_posted) - (ta->date_posted < tb->date_posted);
1618}
1619
1620static gboolean
1621get_corr_account_split(const Split *sa, const Split **retval)
1622{
1623 *retval = nullptr;
1624 g_return_val_if_fail(sa, FALSE);
1625
1626 if (xaccTransCountSplits (sa->parent) > 2)
1627 return FALSE;
1628
1629 *retval = xaccSplitGetOtherSplit (sa);
1630 if (*retval)
1631 return TRUE;
1632 else
1633 return FALSE;
1634}
1635
1636/* TODO: these static consts can be shared. */
1637const char *
1639{
1640 static const char *split_const = nullptr;
1641 const Split *other_split;
1642
1643 if (!get_corr_account_split(sa, &other_split))
1644 {
1645 if (!split_const)
1646 split_const = _("-- Split Transaction --");
1647
1648 return split_const;
1649 }
1650
1651 return xaccAccountGetName(other_split->acc);
1652}
1653
1654char *
1656{
1657 static const char *split_const = nullptr;
1658 const Split *other_split;
1659
1660 if (!get_corr_account_split(sa, &other_split))
1661 {
1662 if (!split_const)
1663 split_const = _("-- Split Transaction --");
1664
1665 return g_strdup(split_const);
1666 }
1667 return gnc_account_get_full_name(other_split->acc);
1668}
1669
1670const char *
1672{
1673 static const char *split_const = nullptr;
1674 const Split *other_split;
1675
1676 if (!get_corr_account_split(sa, &other_split))
1677 {
1678 if (!split_const)
1679 split_const = C_("Displayed account code of the other account in a multi-split transaction", "Split");
1680
1681 return split_const;
1682 }
1683 return xaccAccountGetCode(other_split->acc);
1684}
1685
1686/* TODO: It's not too hard to make this function avoid the malloc/free. */
1687int
1688xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
1689{
1690 Account *aa, *ab;
1691 if (sa == sb) return 0;
1692 if (!sa) return -1;
1693 if (!sb) return 1;
1694
1695 aa = sa->acc;
1696 ab = sb->acc;
1697 if (aa == ab) return 0;
1698
1699 auto path_a = gnc_account_get_all_parents (aa);
1700 auto path_b = gnc_account_get_all_parents (ab);
1701 auto mismatch_pair = std::mismatch (path_a.rbegin(), path_a.rend(),
1702 path_b.rbegin(), path_b.rend());
1703
1704 return mismatch_pair.first == path_a.rend() ? -1
1705 : mismatch_pair.second == path_b.rend() ? 1
1706 : g_utf8_collate (xaccAccountGetName (*mismatch_pair.first),
1707 xaccAccountGetName (*mismatch_pair.second));
1708}
1709
1710
1711int
1712xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
1713{
1714 Account *aa, *ab;
1715 if (!sa && !sb) return 0;
1716 if (!sa) return -1;
1717 if (!sb) return 1;
1718
1719 aa = sa->acc;
1720 ab = sb->acc;
1721
1722 return g_strcmp0(xaccAccountGetCode(aa), xaccAccountGetCode(ab));
1723}
1724
1725int
1726xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
1727{
1728 char *ca, *cb;
1729 int retval;
1730 if (!sa && !sb) return 0;
1731 if (!sa) return -1;
1732 if (!sb) return 1;
1733
1734 /* doesn't matter what separator we use
1735 * as long as they are the same
1736 */
1737
1740 retval = g_strcmp0(ca, cb);
1741 g_free(ca);
1742 g_free(cb);
1743 return retval;
1744}
1745
1746int
1747xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
1748{
1749 const char *ca, *cb;
1750 if (!sa && !sb) return 0;
1751 if (!sa) return -1;
1752 if (!sb) return 1;
1753
1756 return g_strcmp0(ca, cb);
1757}
1758
1759static void
1760qofSplitSetMemo (Split *split, const char* memo)
1761{
1762 g_return_if_fail(split);
1763 CACHE_REPLACE(split->memo, memo);
1764}
1765
1766void
1767xaccSplitSetMemo (Split *split, const char *memo)
1768{
1769 if (!split || !memo) return;
1770 xaccTransBeginEdit (split->parent);
1771
1772 CACHE_REPLACE(split->memo, memo);
1773 qof_instance_set_dirty(QOF_INSTANCE(split));
1774 xaccTransCommitEdit(split->parent);
1775
1776}
1777
1778static void
1779qofSplitSetAction (Split *split, const char *actn)
1780{
1781 g_return_if_fail(split);
1782 CACHE_REPLACE(split->action, actn);
1783}
1784
1785void
1786xaccSplitSetAction (Split *split, const char *actn)
1787{
1788 if (!split || !actn) return;
1789 xaccTransBeginEdit (split->parent);
1790
1791 CACHE_REPLACE(split->action, actn);
1792 qof_instance_set_dirty(QOF_INSTANCE(split));
1793 xaccTransCommitEdit(split->parent);
1794
1795}
1796
1797static void
1798qofSplitSetReconcile (Split *split, char recn)
1799{
1800 g_return_if_fail(split);
1801 switch (recn)
1802 {
1803 case NREC:
1804 case CREC:
1805 case YREC:
1806 case FREC:
1807 case VREC:
1808 split->reconciled = recn;
1809 mark_split (split);
1810 xaccAccountRecomputeBalance (split->acc);
1811 break;
1812 default:
1813 PERR("Bad reconciled flag");
1814 break;
1815 }
1816}
1817
1818void
1819xaccSplitSetReconcile (Split *split, char recn)
1820{
1821 if (!split || split->reconciled == recn) return;
1822 xaccTransBeginEdit (split->parent);
1823
1824 switch (recn)
1825 {
1826 case NREC:
1827 case CREC:
1828 case YREC:
1829 case FREC:
1830 case VREC:
1831 split->reconciled = recn;
1832 mark_split (split);
1833 qof_instance_set_dirty(QOF_INSTANCE(split));
1834 xaccAccountRecomputeBalance (split->acc);
1835 break;
1836 default:
1837 PERR("Bad reconciled flag");
1838 break;
1839 }
1840 xaccTransCommitEdit(split->parent);
1841
1842}
1843
1844void
1846{
1847 if (!split) return;
1848 xaccTransBeginEdit (split->parent);
1849
1850 split->date_reconciled = secs;
1851 qof_instance_set_dirty(QOF_INSTANCE(split));
1852 xaccTransCommitEdit(split->parent);
1853
1854}
1855
1856
1857/*################## Added for Reg2 #################*/
1858time64
1859xaccSplitGetDateReconciled (const Split * split)
1860{
1861 return split ? split->date_reconciled : 0;
1862}
1863/*################## Added for Reg2 #################*/
1864
1865/********************************************************************\
1866\********************************************************************/
1867
1868/* return the parent transaction of the split */
1869Transaction *
1870xaccSplitGetParent (const Split *split)
1871{
1872 return split ? split->parent : nullptr;
1873}
1874
1875void
1876xaccSplitSetParent(Split *s, Transaction *t)
1877{
1878 Transaction *old_trans;
1879 GncEventData ed;
1880
1881 g_return_if_fail(s);
1882 if (s->parent == t) return;
1883
1884 if (s->parent != s->orig_parent && s->orig_parent != t)
1885 PERR("You may not add the split to more than one transaction"
1886 " during the BeginEdit/CommitEdit block.");
1888 old_trans = s->parent;
1889
1890 xaccTransBeginEdit(old_trans);
1891
1892 ed.node = s;
1893 if (old_trans)
1894 {
1895 ed.idx = xaccTransGetSplitIndex(old_trans, s);
1896 qof_event_gen(&old_trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1897 }
1898 s->parent = t;
1899 qof_instance_set_dirty(QOF_INSTANCE(s));
1900
1901 xaccTransCommitEdit(old_trans);
1902
1903 if (t)
1904 {
1905 /* Convert split to new transaction's commodity denominator */
1907
1908 /* add ourselves to the new transaction's list of pending splits. */
1909 if (nullptr == g_list_find(t->splits, s))
1910 t->splits = g_list_append(t->splits, s);
1911
1912 ed.idx = -1; /* unused */
1913 qof_event_gen(&t->inst, GNC_EVENT_ITEM_ADDED, &ed);
1914 }
1916}
1917
1918
1919GNCLot *
1920xaccSplitGetLot (const Split *split)
1921{
1922 return split ? split->lot : nullptr;
1923}
1924
1925void
1926xaccSplitSetLot(Split* split, GNCLot* lot)
1927{
1928 xaccTransBeginEdit (split->parent);
1929 split->lot = lot;
1930 qof_instance_set_dirty(QOF_INSTANCE(split));
1931 xaccTransCommitEdit(split->parent);
1932}
1933
1934const char *
1935xaccSplitGetMemo (const Split *split)
1936{
1937 return split ? split->memo : nullptr;
1938}
1939
1940void
1941xaccSplitSetOnlineID (Split *split, const char *id)
1942{
1943 if (!split) return;
1944 /* No xaccTransBeginEdit/CommitEdit here: the online_id is normally set
1945 * while many other parameters of a transaction are being changed, so
1946 * the caller wraps this in the parent transaction's edit. */
1947 std::optional<const char*> val;
1948 if (id && *id)
1949 val = g_strdup (id);
1950 qof_instance_set_path_kvp<const char*> (QOF_INSTANCE(split), val, {split_online_id});
1951 qof_instance_set_dirty (QOF_INSTANCE(split));
1952}
1953
1954const char *
1955xaccSplitGetOnlineID (const Split *split)
1956{
1957 if (!split) return nullptr;
1958 auto rv{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(split), {split_online_id})};
1959 return rv ? *rv : nullptr;
1960}
1961
1962gboolean
1963xaccSplitHasOnlineID (const Split *split)
1964{
1965 auto id = xaccSplitGetOnlineID (split);
1966 return (id && *id);
1967}
1968
1969const char *
1970xaccSplitGetAction (const Split *split)
1971{
1972 return split ? split->action : nullptr;
1973}
1974
1975char
1976xaccSplitGetReconcile (const Split *split)
1977{
1978 return split ? split->reconciled : ' ';
1979}
1980
1981
1982gnc_numeric
1983xaccSplitGetAmount (const Split * split)
1984{
1985 return split ? split->amount : gnc_numeric_zero();
1986}
1987
1988gnc_numeric
1989xaccSplitGetValue (const Split * split)
1990{
1991 return split ? split->value : gnc_numeric_zero();
1992}
1993
1994gnc_numeric
1995xaccSplitGetSharePrice (const Split * split)
1996{
1997 gnc_numeric amt, val, price;
1998 if (!split) return gnc_numeric_create(0, 1);
1999
2000
2001 /* if amount == 0, return 0
2002 * otherwise return value/amount
2003 */
2004
2005 amt = xaccSplitGetAmount(split);
2006 val = xaccSplitGetValue(split);
2007 if (gnc_numeric_zero_p(amt))
2008 return gnc_numeric_create(0, 1);
2009
2010 price = gnc_numeric_div(val, amt,
2013
2014 /* During random checks we can get some very weird prices. Let's
2015 * handle some overflow and other error conditions by returning
2016 * zero. But still print an error to let us know it happened.
2017 */
2018 if (gnc_numeric_check(price))
2019 {
2020 PERR("Computing share price failed (%d): [ %" G_GINT64_FORMAT " / %"
2021 G_GINT64_FORMAT " ] / [ %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " ]",
2022 gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
2023 return gnc_numeric_create(0, 1);
2024 }
2025
2026 return price;
2027}
2028
2029/********************************************************************\
2030\********************************************************************/
2031
2032QofBook *
2033xaccSplitGetBook (const Split *split)
2034{
2035 return qof_instance_get_book(QOF_INSTANCE(split));
2036}
2037
2038const char *
2040{
2041 if (!s) return nullptr;
2042
2043 if (!s->split_type)
2044 {
2045 auto type{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(s), {"split-type"})};
2046
2047 if (!type || !g_strcmp0 (*type, split_type_normal))
2048 s->split_type = split_type_normal;
2049 else if (!g_strcmp0 (*type, split_type_stock_split))
2050 s->split_type = split_type_stock_split;
2051 else
2052 {
2053 PERR ("unexpected split-type %s, reset to normal.", *type);
2054 s->split_type = split_type_normal;
2055 }
2056 }
2057 return s->split_type;
2058}
2059
2060/* reconfigure a split to be a stock split - after this, you shouldn't
2061 mess with the value, just the amount. */
2062void
2064{
2065 xaccTransBeginEdit (s->parent);
2066
2067 s->value = gnc_numeric_zero();
2068 s->split_type = split_type_stock_split;
2069 qof_instance_set_path_kvp<const char*> (QOF_INSTANCE(s), g_strdup(split_type_stock_split),
2070 {"split-type"});
2071 SET_GAINS_VDIRTY(s);
2072 mark_split(s);
2073 qof_instance_set_dirty(QOF_INSTANCE(s));
2074 xaccTransCommitEdit(s->parent);
2075}
2076
2077gboolean
2079{
2080 return g_strcmp0(split_type_stock_split, xaccSplitGetType(s)) == 0;
2081}
2082
2083void
2084xaccSplitAddPeerSplit (Split *split, const Split *other_split,
2085 time64 timestamp)
2086{
2087 const GncGUID* guid;
2088
2089 g_return_if_fail (split != nullptr);
2090 g_return_if_fail (other_split != nullptr);
2091
2092 guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2093 xaccTransBeginEdit (split->parent);
2094 qof_instance_kvp_add_guid (QOF_INSTANCE (split), "lot-split",
2095 gnc_time(nullptr), "peer_guid", guid_copy(guid));
2096 mark_split (split);
2097 qof_instance_set_dirty (QOF_INSTANCE (split));
2098 xaccTransCommitEdit (split->parent);
2099}
2100
2101gboolean
2102xaccSplitHasPeers (const Split *split)
2103{
2104 return qof_instance_has_slot (QOF_INSTANCE (split), "lot-split");
2105}
2106
2107gboolean
2108xaccSplitIsPeerSplit (const Split *split, const Split *other_split)
2109{
2110 const GncGUID* guid;
2111
2112 g_return_val_if_fail (split != nullptr, FALSE);
2113 g_return_val_if_fail (other_split != nullptr, FALSE);
2114
2115 guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2116 return qof_instance_kvp_has_guid (QOF_INSTANCE (split), "lot-split",
2117 "peer_guid", guid);
2118}
2119
2120void
2121xaccSplitRemovePeerSplit (Split *split, const Split *other_split)
2122{
2123 const GncGUID* guid;
2124
2125 g_return_if_fail (split != nullptr);
2126 g_return_if_fail (other_split != nullptr);
2127
2128 guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2129 xaccTransBeginEdit (split->parent);
2130 qof_instance_kvp_remove_guid (QOF_INSTANCE (split), "lot-split",
2131 "peer_guid", guid);
2132 mark_split (split);
2133 qof_instance_set_dirty (QOF_INSTANCE (split));
2134 xaccTransCommitEdit (split->parent);
2135}
2136
2137void
2138xaccSplitMergePeerSplits (Split *split, const Split *other_split)
2139{
2140 xaccTransBeginEdit (split->parent);
2141 qof_instance_kvp_merge_guids (QOF_INSTANCE (split),
2142 QOF_INSTANCE (other_split), "lot-split");
2143 mark_split (split);
2144 qof_instance_set_dirty (QOF_INSTANCE (split));
2145 xaccTransCommitEdit (split->parent);
2146}
2147
2148/********************************************************************\
2149\********************************************************************/
2150/* In the old world, the 'other split' was the other split of a
2151 * transaction that contained only two splits. In the new world,
2152 * a split may have been cut up between multiple lots, although
2153 * in a conceptual sense, if lots hadn't been used, there would be
2154 * only a pair. So we handle this conceptual case: we can still
2155 * identify, unambiguously, the 'other' split when 'this' split
2156 * as been cut up across lots. We do this by looking for the
2157 * 'lot-split' keyword, which occurs only in cut-up splits.
2158 */
2159
2160Split *
2161xaccSplitGetOtherSplit (const Split *split)
2162{
2163 Transaction *trans;
2164 Split *other = nullptr;
2165
2166 if (!split) return nullptr;
2167 trans = split->parent;
2168 if (!trans) return nullptr;
2169
2170 for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
2171 {
2172 Split *s = GNC_SPLIT(n->data);
2173 if ((s == split) ||
2174 (!xaccTransStillHasSplit(trans, s)) ||
2176 (qof_instance_has_slot (QOF_INSTANCE (s), "lot-split")))
2177 continue;
2178
2179 if (other)
2180 return nullptr;
2181
2182 other = s;
2183 }
2184 return other;
2185}
2186
2187/********************************************************************\
2188\********************************************************************/
2189
2190gnc_numeric
2191xaccSplitVoidFormerAmount(const Split *split)
2192{
2193 g_return_val_if_fail(split, gnc_numeric_zero());
2194 auto num{qof_instance_get_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {void_former_amt_str})};
2195 return num ? *num : gnc_numeric_zero();
2196}
2197
2198gnc_numeric
2199xaccSplitVoidFormerValue(const Split *split)
2200{
2201 g_return_val_if_fail(split, gnc_numeric_zero());
2202 auto num{qof_instance_get_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {void_former_val_str})};
2203 return num ? *num : gnc_numeric_zero();
2204}
2205
2206void
2207xaccSplitVoid(Split *split)
2208{
2209 g_return_if_fail (GNC_IS_SPLIT(split));
2210 qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), xaccSplitGetAmount(split), {void_former_amt_str});
2211 qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), xaccSplitGetValue(split), {void_former_val_str});
2212 qof_instance_set_dirty (QOF_INSTANCE(split));
2213
2214 static gnc_numeric zero = gnc_numeric_zero();
2215 xaccSplitSetAmount (split, zero);
2216 xaccSplitSetValue (split, zero);
2218}
2219
2220void
2221xaccSplitUnvoid(Split *split)
2222{
2223 g_return_if_fail (GNC_IS_SPLIT(split));
2227 qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {}, {void_former_amt_str});
2228 qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(split), {}, {void_former_val_str});
2229 qof_instance_set_dirty (QOF_INSTANCE(split));
2230}
2231
2232/********************************************************************\
2233\********************************************************************/
2234/* QofObject function implementation */
2235
2236/* Hook into the QofObject registry */
2237
2238#ifdef _MSC_VER
2239/* MSVC compiler doesn't have C99 "designated initializers"
2240 * so we wrap them in a macro that is empty on MSVC. */
2241# define DI(x) /* */
2242#else
2243# define DI(x) x
2244#endif
2245static QofObject split_object_def =
2246{
2247 DI(.interface_version = ) QOF_OBJECT_VERSION,
2248 DI(.e_type = ) GNC_ID_SPLIT,
2249 DI(.type_label = ) "Split",
2250 DI(.create = ) (void* (*)(QofBook*))xaccMallocSplit,
2251 DI(.book_begin = ) nullptr,
2252 DI(.book_end = ) nullptr,
2253 DI(.is_dirty = ) qof_collection_is_dirty,
2254 DI(.mark_clean = ) qof_collection_mark_clean,
2255 DI(.foreach = ) qof_collection_foreach,
2256 DI(.printable = ) (const char * (*)(gpointer)) xaccSplitGetMemo,
2257 DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
2258};
2259
2260static gpointer
2261split_account_guid_getter (gpointer obj, const QofParam *p)
2262{
2263 Split *s = GNC_SPLIT(obj);
2264 Account *acc;
2265
2266 if (!s) return nullptr;
2267 acc = xaccSplitGetAccount (s);
2268 if (!acc) return nullptr;
2269 return ((gpointer)xaccAccountGetGUID (acc));
2270}
2271
2272static double /* internal use only */
2273DxaccSplitGetShareAmount (const Split * split)
2274{
2275 return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
2276}
2277
2278static gpointer
2279no_op (gpointer obj, const QofParam *p)
2280{
2281 return obj;
2282}
2283
2284static void
2285qofSplitSetParentTrans(Split *s, QofInstance *ent)
2286{
2287 Transaction *trans = (Transaction*)ent;
2288
2289 g_return_if_fail(trans);
2290 xaccSplitSetParent(s, trans);
2291}
2292
2293static void
2294qofSplitSetAccount(Split *s, QofInstance *ent)
2295{
2296 Account *acc = (Account*)ent;
2297
2298 g_return_if_fail(acc);
2299 xaccSplitSetAccount(s, acc);
2300}
2301
2302gboolean xaccSplitRegister (void)
2303{
2304 static const QofParam params[] =
2305 {
2306 {
2307 SPLIT_DATE_RECONCILED, QOF_TYPE_DATE,
2310 },
2311
2312 /* d-* are deprecated query params, should not be used in new
2313 * queries, should be removed from old queries. */
2314 {
2315 "d-share-amount", QOF_TYPE_DOUBLE,
2316 (QofAccessFunc)DxaccSplitGetShareAmount, nullptr
2317 },
2318 {
2319 "d-share-int64", QOF_TYPE_INT64,
2321 },
2322 {
2323 SPLIT_BALANCE, QOF_TYPE_NUMERIC,
2325 },
2326 {
2327 SPLIT_CLEARED_BALANCE, QOF_TYPE_NUMERIC,
2329 },
2330 {
2331 SPLIT_RECONCILED_BALANCE, QOF_TYPE_NUMERIC,
2333 },
2334 {
2335 SPLIT_MEMO, QOF_TYPE_STRING,
2337 },
2338 {
2339 SPLIT_ACTION, QOF_TYPE_STRING,
2341 },
2342 {
2343 SPLIT_RECONCILE, QOF_TYPE_CHAR,
2345 (QofSetterFunc)qofSplitSetReconcile
2346 },
2347 {
2348 SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
2350 },
2351 {
2352 SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
2354 (QofSetterFunc)qofSplitSetSharePrice
2355 },
2356 {
2357 SPLIT_VALUE, QOF_TYPE_DEBCRED,
2359 },
2360 { SPLIT_TYPE, QOF_TYPE_STRING, (QofAccessFunc)xaccSplitGetType, nullptr },
2361 {
2362 SPLIT_VOIDED_AMOUNT, QOF_TYPE_NUMERIC,
2364 },
2365 {
2366 SPLIT_VOIDED_VALUE, QOF_TYPE_NUMERIC,
2368 },
2369 { SPLIT_LOT, GNC_ID_LOT, (QofAccessFunc)xaccSplitGetLot, nullptr },
2370 {
2371 SPLIT_TRANS, GNC_ID_TRANS,
2373 (QofSetterFunc)qofSplitSetParentTrans
2374 },
2375 {
2376 SPLIT_ACCOUNT, GNC_ID_ACCOUNT,
2377 (QofAccessFunc)xaccSplitGetAccount, (QofSetterFunc)qofSplitSetAccount
2378 },
2379 { SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, nullptr },
2380 /* these are no-ops to register the parameter names (for sorting) but
2381 they return an allocated object which getters cannot do. */
2382 { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, nullptr },
2383 { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, nullptr },
2384 { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, nullptr },
2385 { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, nullptr },
2386 {
2387 QOF_PARAM_GUID, QOF_TYPE_GUID,
2389 },
2390 { nullptr },
2391 };
2392
2393 qof_class_register (GNC_ID_SPLIT, (QofSortFunc)xaccSplitOrder, params);
2394 qof_class_register (SPLIT_ACCT_FULLNAME,
2396 qof_class_register (SPLIT_CORR_ACCT_NAME,
2398 nullptr);
2399 qof_class_register (SPLIT_CORR_ACCT_CODE,
2401
2402 return qof_object_register (&split_object_def);
2403}
2404
2406_utest_split_fill_functions (void)
2407{
2408 SplitTestFunctions *func = g_new (SplitTestFunctions, 1);
2409
2410 func->xaccSplitEqualCheckBal = xaccSplitEqualCheckBal;
2411 func->get_currency_denom = get_currency_denom;
2412 func->get_commodity_denom = get_commodity_denom;
2413 func->get_corr_account_split = get_corr_account_split;
2414 return func;
2415}
2416
2417/************************ END OF ************************************\
2418\************************* FILE *************************************/
This is the private header for the account structure.
Account public routines (C++ api)
convert single-entry accounts to clean double-entry
API for Transactions and Splits (journal entries)
API for the transaction logger.
Utilities to Automatically Compute Capital Gains/Losses.
Commodity handling public routines.
All type declarations for the whole Gnucash engine.
Additional event handling code.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition Account.cpp:3289
void xaccAccountRecomputeBalance(Account *acc)
The following recompute the partial balances (stored with the transaction) and the total balance,...
Definition Account.cpp:2275
gboolean gnc_account_insert_split(Account *acc, Split *s)
Insert the given split from an account.
Definition Account.cpp:1943
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition Account.cpp:3305
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3267
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition Account.cpp:2745
#define xaccAccountGetGUID(X)
Definition Account.h:252
gboolean gnc_account_remove_split(Account *acc, Split *s)
Remove the given split from an account.
Definition Account.cpp:1973
const char * xaccAccountGetCode(const Account *acc)
Get the account's accounting code.
Definition Account.cpp:3336
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
@ ACCT_TYPE_TRADING
Account used to record multiple commodity transactions.
Definition Account.h:155
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition qofbackend.h:58
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition qofbook.cpp:521
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the 'Num' field, FALSE if it uses transaction nu...
Split * xaccSplitGetCapGainsSplit(const Split *split)
The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split.
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition qofclass.h:123
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition qofclass.h:130
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
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition qofclass.h:168
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
Retrieve the 'print' name for the specified commodity.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition gnc-date.h:108
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
size_t qof_print_date_buff(char *buff, const size_t len, time64 t)
Convenience: calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:574
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.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gboolean xaccTransIsBalanced(const Transaction *trans)
Returns true if the transaction is balanced according to the rules currently in effect.
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition Account.cpp:2140
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
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.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account.
Definition Account.h:1069
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_guids, gboolean check_splits, gboolean check_balances, gboolean assume_ordered)
Equality.
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition qofid.cpp:209
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of 'dirty' flag on collection.
Definition qofid.cpp:232
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition qofevent.cpp:231
#define GNC_EVENT_ITEM_ADDED
These events are used when a split is added to an account.
Definition gnc-event.h:45
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition guid.cpp:155
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
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
void qof_instance_copy_book(gpointer ptr1, gconstpointer ptr2)
Copy the book from one QofInstances to another.
#define qof_instance_is_dirty
Return value of is_dirty flag.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
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.
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
gboolean qof_instance_books_equal(gconstpointer ptr1, gconstpointer ptr2)
See if two QofInstances share the same book.
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
guint32 qof_instance_get_idata(gconstpointer inst)
get the instance tag number used for kvp management in sql backends.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
Retrieves the contents of a KVP slot into a provided GValue.
void qof_instance_set_kvp(QofInstance *, GValue const *value, unsigned count,...)
Sets a KVP slot to a value from a GValue.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
void gnc_lot_add_split(GNCLot *lot, Split *split)
Adds a split to this lot.
Definition gnc-lot.cpp:579
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition gnc-lot.cpp:377
void gnc_lot_remove_split(GNCLot *lot, Split *split)
Adds a split from this lot.
Definition gnc-lot.cpp:631
void gnc_lot_set_closed_unknown(GNCLot *lot)
Reset closed flag so that it will be recalculated.
Definition gnc-lot.cpp:414
const char * gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
Returns a string representation of the given GNCNumericErrorCode.
double gnc_numeric_to_double(gnc_numeric in)
Convert numeric to floating-point value.
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 ...
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
@ GNC_ERROR_OK
No error.
@ GNC_HOW_RND_ROUND_HALF_UP
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition qofid.cpp:238
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition qofobject.h:63
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition qofquery.h:108
int xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
Compare two splits by code of account.
Definition Split.cpp:1712
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition Split.cpp:1870
void xaccSplitSetAdjustedAmount(Split *s, gnc_numeric amt)
Sets the stock split adjusted amount of a split.
Definition Split.cpp:1346
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Definition Split.cpp:1819
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition Split.cpp:1506
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Definition Split.cpp:1976
#define SPLIT_ACCOUNT_GUID
for guid_match_all
Definition Split.h:571
gnc_numeric xaccSplitGetClearedBalance(const Split *s)
The cleared-balance is the currency-denominated balance of all transactions that have been marked as ...
Definition Split.cpp:1328
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition Split.cpp:1767
int xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
Compare two splits by full name of the other account.
Definition Split.cpp:1726
void xaccSplitSetSharePrice(Split *s, gnc_numeric price)
Definition Split.cpp:1205
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition Split.cpp:1536
void xaccSplitMergePeerSplits(Split *split, const Split *other_split)
Merge the other_split's peer splits into split's peers.
Definition Split.cpp:2138
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id,...
Definition Split.cpp:1091
#define xaccSplitGetGUID(X)
Definition Split.h:579
void xaccSplitSetValue(Split *s, gnc_numeric amt)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
Definition Split.cpp:1280
const char * xaccSplitGetCorrAccountName(const Split *sa)
document me
Definition Split.cpp:1638
void xaccSplitRemovePeerSplit(Split *split, const Split *other_split)
Remove a peer split from this split's lot-split list.
Definition Split.cpp:2121
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition Split.cpp:539
gnc_numeric xaccSplitGetNoclosingBalance(const Split *s)
The noclosing-balance is the currency-denominated balance of all transactions except 'closing' transa...
Definition Split.cpp:1322
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
Definition Split.cpp:1243
const char * xaccSplitGetAction(const Split *split)
Returns the action string.
Definition Split.cpp:1970
#define VREC
split is void
Definition Split.h:77
const char * xaccSplitGetType(Split *s)
Returns the split type, which is either the string "normal", or "stock-split" for a split from a stoc...
Definition Split.cpp:2039
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn't be...
Definition Split.cpp:1920
char * xaccSplitGetCorrAccountFullName(const Split *sa)
These functions take a split, get the corresponding split on the "other side" of the transaction,...
Definition Split.cpp:1655
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition Split.cpp:1859
gnc_numeric xaccSplitVoidFormerValue(const Split *split)
Returns the original pre-void value of a split.
Definition Split.cpp:2199
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Definition Split.cpp:1989
void xaccSplitSetLot(Split *split, GNCLot *lot)
Assigns the split to a specific Lot.
Definition Split.cpp:1926
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
Definition Split.cpp:1995
const char * xaccSplitGetCorrAccountCode(const Split *sa)
document me
Definition Split.cpp:1671
int xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
Compare two splits by full name of account.
Definition Split.cpp:1688
gnc_numeric xaccSplitGetReconciledBalance(const Split *s)
Returns the reconciled-balance of this split.
Definition Split.cpp:1334
gboolean xaccSplitEqual(const Split *sa, const Split *sb, gboolean check_guids, gboolean check_balances, gboolean check_txn_splits)
Equality.
Definition Split.cpp:819
gboolean xaccSplitHasPeers(const Split *split)
Does this split have peers?
Definition Split.cpp:2102
Account * xaccSplitGetAccount(const Split *s)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition Split.cpp:956
int xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
Compare two splits by code of the other account.
Definition Split.cpp:1747
void xaccSplitCopyOnto(const Split *from_split, Split *to_split)
This is really a helper for xaccTransCopyOnto.
Definition Split.cpp:648
void xaccSplitSetSharePriceAndAmount(Split *s, gnc_numeric price, gnc_numeric amt)
The xaccSplitSetSharePriceAndAmount() method will simultaneously update the share price and the numbe...
Definition Split.cpp:1177
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition Split.cpp:1935
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64.
Definition Split.cpp:1845
gnc_numeric xaccSplitVoidFormerAmount(const Split *split)
Returns the original pre-void amount of a split.
Definition Split.cpp:2191
void xaccSplitSetOnlineID(Split *split, const char *id)
The online_id is the OFX/HBCI "FITID" recorded on a split when it is imported.
Definition Split.cpp:1941
void xaccSplitSetBaseValue(Split *s, gnc_numeric value, const gnc_commodity *base_currency)
Depending on the base_currency, set either the value or the amount of this split or both: If the base...
Definition Split.cpp:1355
gnc_numeric xaccSplitGetBaseValue(const Split *s, const gnc_commodity *base_currency)
Depending on the base_currency, return either the value or the amount of this split: If the base_curr...
Definition Split.cpp:1410
#define NREC
not reconciled or cleared
Definition Split.h:76
const char * xaccSplitGetOnlineID(const Split *split)
Returns the split's online_id.
Definition Split.cpp:1955
#define FREC
frozen into accounting period
Definition Split.h:75
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits.
Definition Split.cpp:2161
QofBook * xaccSplitGetBook(const Split *split)
Returns the book of this split, i.e.
Definition Split.cpp:2033
gnc_numeric xaccSplitGetAdjustedAmount(const Split *s)
Returns the stock-split adjusted amount of the split in the account's commodity.
Definition Split.cpp:1340
#define CREC
The Split has been cleared
Definition Split.h:73
void xaccSplitAddPeerSplit(Split *split, const Split *other_split, time64 timestamp)
Add a peer split to this split's lot-split list.
Definition Split.cpp:2084
gnc_numeric xaccSplitGetBalance(const Split *s)
Returns the running balance up to and including the indicated split.
Definition Split.cpp:1316
gboolean xaccSplitIsPeerSplit(const Split *split, const Split *other_split)
Report if a split is a peer of this one.
Definition Split.cpp:2108
#define YREC
The Split has been reconciled.
Definition Split.h:74
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition Split.cpp:1786
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
Definition Split.cpp:2078
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Definition Split.cpp:1983
void xaccSplitMakeStockSplit(Split *s)
Mark a split to be of type stock split - after this, you shouldn't modify the value anymore,...
Definition Split.cpp:2063
gboolean xaccSplitHasOnlineID(const Split *split)
Returns TRUE if the split has a non-empty online_id.
Definition Split.cpp:1963
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
Encapsulate all the information about a dataset.
Object instance holds common fields that most gnucash objects use.
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47