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