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