GnuCash fec5643+
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
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
1158static inline int
1159get_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
1171static inline int
1172get_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
1187void
1188xaccSplitSetSharePriceAndAmount (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
1206static void
1207qofSplitSetSharePrice (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),
1212 GNC_HOW_RND_ROUND_HALF_UP);
1213}
1214
1215void
1216xaccSplitSetSharePrice (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
1237static void
1238qofSplitSetAmount (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. */
1253void
1254xaccSplitSetAmount (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
1280static void
1281qofSplitSetValue (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. */
1290void
1291xaccSplitSetValue (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
1326gnc_numeric
1327xaccSplitGetBalance (const Split *s)
1328{
1329 return s ? s->balance : gnc_numeric_zero();
1330}
1331
1332gnc_numeric
1334{
1335 return s ? s->noclosing_balance : gnc_numeric_zero();
1336}
1337
1338gnc_numeric
1340{
1341 return s ? s->cleared_balance : gnc_numeric_zero();
1342}
1343
1344gnc_numeric
1346{
1347 return s ? s->reconciled_balance : gnc_numeric_zero();
1348}
1349
1350gnc_numeric
1352{
1353 return s ? s->adjusted_amount : gnc_numeric_zero();
1354}
1355
1356void
1357xaccSplitSetAdjustedAmount (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
1365void
1366xaccSplitSetBaseValue (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),
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
1420gnc_numeric
1421xaccSplitGetBaseValue (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
1443gnc_numeric
1444xaccSplitConvertAmount (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),
1510 GNC_HOW_RND_ROUND_HALF_UP);
1511}
1512
1513/********************************************************************\
1514\********************************************************************/
1515
1516gboolean
1517xaccSplitDestroy (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)
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
1546gint
1547xaccSplitOrder (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
1610gint
1611xaccSplitOrderDateOnly (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
1631static gboolean
1632get_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. */
1648const 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
1665char *
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
1681const 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. */
1698int
1699xaccSplitCompareAccountFullNames(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
1722int
1723xaccSplitCompareAccountCodes(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
1736int
1737xaccSplitCompareOtherAccountFullNames(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
1757int
1758xaccSplitCompareOtherAccountCodes(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
1767 return g_strcmp0(ca, cb);
1768}
1769
1770static void
1771qofSplitSetMemo (Split *split, const char* memo)
1772{
1773 g_return_if_fail(split);
1774 CACHE_REPLACE(split->memo, memo);
1775}
1776
1777void
1778xaccSplitSetMemo (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
1789static void
1790qofSplitSetAction (Split *split, const char *actn)
1791{
1792 g_return_if_fail(split);
1793 CACHE_REPLACE(split->action, actn);
1794}
1795
1796void
1797xaccSplitSetAction (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
1808static void
1809qofSplitSetReconcile (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
1829void
1830xaccSplitSetReconcile (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
1855void
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 #################*/
1869time64
1870xaccSplitGetDateReconciled (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 */
1880Transaction *
1881xaccSplitGetParent (const Split *split)
1882{
1883 return split ? split->parent : nullptr;
1884}
1885
1886void
1887xaccSplitSetParent(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.");
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
1930GNCLot *
1931xaccSplitGetLot (const Split *split)
1932{
1933 return split ? split->lot : nullptr;
1934}
1935
1936void
1937xaccSplitSetLot(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
1945const char *
1946xaccSplitGetMemo (const Split *split)
1947{
1948 return split ? split->memo : nullptr;
1949}
1950
1951void
1952xaccSplitSetOnlineID (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
1965const char *
1966xaccSplitGetOnlineID (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
1973gboolean
1974xaccSplitHasOnlineID (const Split *split)
1975{
1976 auto id = xaccSplitGetOnlineID (split);
1977 return (id && *id);
1978}
1979
1980const char *
1981xaccSplitGetAction (const Split *split)
1982{
1983 return split ? split->action : nullptr;
1984}
1985
1986char
1987xaccSplitGetReconcile (const Split *split)
1988{
1989 return split ? split->reconciled : ' ';
1990}
1991
1992
1993gnc_numeric
1994xaccSplitGetAmount (const Split * split)
1995{
1996 return split ? split->amount : gnc_numeric_zero();
1997}
1998
1999gnc_numeric
2000xaccSplitGetValue (const Split * split)
2001{
2002 return split ? split->value : gnc_numeric_zero();
2003}
2004
2005gnc_numeric
2006xaccSplitGetSharePrice (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
2043QofBook *
2044xaccSplitGetBook (const Split *split)
2045{
2046 return qof_instance_get_book(QOF_INSTANCE(split));
2047}
2048
2049const 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. */
2073void
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
2088gboolean
2090{
2091 return g_strcmp0(split_type_stock_split, xaccSplitGetType(s)) == 0;
2092}
2093
2094void
2095xaccSplitAddPeerSplit (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
2112gboolean
2113xaccSplitHasPeers (const Split *split)
2114{
2115 return qof_instance_has_slot (QOF_INSTANCE (split), "lot-split");
2116}
2117
2118gboolean
2119xaccSplitIsPeerSplit (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
2131void
2132xaccSplitRemovePeerSplit (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
2148void
2149xaccSplitMergePeerSplits (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
2171Split *
2172xaccSplitGetOtherSplit (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
2201gnc_numeric
2202xaccSplitVoidFormerAmount(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
2209gnc_numeric
2210xaccSplitVoidFormerValue(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
2217void
2218xaccSplitVoid(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);
2229}
2230
2231void
2232xaccSplitUnvoid(Split *split)
2233{
2234 g_return_if_fail (GNC_IS_SPLIT(split));
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
2256static 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
2271static gpointer
2272split_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
2283static double /* internal use only */
2284DxaccSplitGetShareAmount (const Split * split)
2285{
2286 return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
2287}
2288
2289static gpointer
2290no_op (gpointer obj, const QofParam *p)
2291{
2292 return obj;
2293}
2294
2295static void
2296qofSplitSetParentTrans(Split *s, QofInstance *ent)
2297{
2298 Transaction *trans = (Transaction*)ent;
2299
2300 g_return_if_fail(trans);
2301 xaccSplitSetParent(s, trans);
2302}
2303
2304static void
2305qofSplitSetAccount(Split *s, QofInstance *ent)
2306{
2307 Account *acc = (Account*)ent;
2308
2309 g_return_if_fail(acc);
2310 xaccSplitSetAccount(s, acc);
2311}
2312
2313gboolean 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,
2348 },
2349 {
2350 SPLIT_ACTION, QOF_TYPE_STRING,
2352 },
2353 {
2354 SPLIT_RECONCILE, QOF_TYPE_CHAR,
2356 (QofSetterFunc)qofSplitSetReconcile
2357 },
2358 {
2359 SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
2361 },
2362 {
2363 SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
2365 (QofSetterFunc)qofSplitSetSharePrice
2366 },
2367 {
2368 SPLIT_VALUE, QOF_TYPE_DEBCRED,
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 *************************************/
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:3277
void xaccAccountRecomputeBalance(Account *acc)
The following recompute the partial balances (stored with the transaction) and the total balance,...
Definition Account.cpp:2263
gboolean gnc_account_insert_split(Account *acc, Split *s)
Insert the given split from an account.
Definition Account.cpp:1931
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
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3255
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition Account.cpp:2733
#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:1961
const char * xaccAccountGetCode(const Account *acc)
Get the account's accounting code.
Definition Account.cpp:3324
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3396
@ 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.
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition qofclass.h:124
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition qofclass.h:131
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:169
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:2128
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:1723
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition Split.cpp:1881
void xaccSplitSetAdjustedAmount(Split *s, gnc_numeric amt)
Sets the stock split adjusted amount of a split.
Definition Split.cpp:1357
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Definition Split.cpp:1830
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition Split.cpp:1517
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Definition Split.cpp:1987
#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:1339
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition Split.cpp:1778
int xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
Compare two splits by full name of the other account.
Definition Split.cpp:1737
void xaccSplitSetSharePrice(Split *s, gnc_numeric price)
Definition Split.cpp:1216
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition Split.cpp:1547
void xaccSplitMergePeerSplits(Split *split, const Split *other_split)
Merge the other_split's peer splits into split's peers.
Definition Split.cpp:2149
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:1291
const char * xaccSplitGetCorrAccountName(const Split *sa)
document me
Definition Split.cpp:1649
void xaccSplitRemovePeerSplit(Split *split, const Split *other_split)
Remove a peer split from this split's lot-split list.
Definition Split.cpp:2132
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:1333
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:1254
const char * xaccSplitGetAction(const Split *split)
Returns the action string.
Definition Split.cpp:1981
#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:2050
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:1931
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
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition Split.cpp:1870
gnc_numeric xaccSplitVoidFormerValue(const Split *split)
Returns the original pre-void value of a split.
Definition Split.cpp:2210
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Definition Split.cpp:2000
void xaccSplitSetLot(Split *split, GNCLot *lot)
Assigns the split to a specific Lot.
Definition Split.cpp:1937
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
Definition Split.cpp:2006
const char * xaccSplitGetCorrAccountCode(const Split *sa)
document me
Definition Split.cpp:1682
int xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
Compare two splits by full name of account.
Definition Split.cpp:1699
gnc_numeric xaccSplitGetReconciledBalance(const Split *s)
Returns the reconciled-balance of this split.
Definition Split.cpp:1345
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
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:1758
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:1188
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition Split.cpp:1946
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
gnc_numeric xaccSplitVoidFormerAmount(const Split *split)
Returns the original pre-void amount of a split.
Definition Split.cpp:2202
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
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
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
#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:1966
#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:2172
QofBook * xaccSplitGetBook(const Split *split)
Returns the book of this split, i.e.
Definition Split.cpp:2044
gnc_numeric xaccSplitGetAdjustedAmount(const Split *s)
Returns the stock-split adjusted amount of the split in the account's commodity.
Definition Split.cpp:1351
#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:2095
gnc_numeric xaccSplitGetBalance(const Split *s)
Returns the running balance up to and including the indicated split.
Definition Split.cpp:1327
gboolean xaccSplitIsPeerSplit(const Split *split, const Split *other_split)
Report if a split is a peer of this one.
Definition Split.cpp:2119
#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:1797
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
Definition Split.cpp:2089
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Definition Split.cpp:1994
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:2074
gboolean xaccSplitHasOnlineID(const Split *split)
Returns TRUE if the split has a non-empty online_id.
Definition Split.cpp:1974
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