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 : 140912 : G_DEFINE_TYPE(Split, gnc_split, QOF_TYPE_INSTANCE)
107 : :
108 : : static void
109 : 9797 : gnc_split_init(Split* split)
110 : : {
111 : : /* fill in some sane defaults */
112 : 9797 : split->acc = nullptr;
113 : 9797 : split->orig_acc = nullptr;
114 : 9797 : split->parent = nullptr;
115 : 9797 : split->lot = nullptr;
116 : :
117 : 9797 : split->action = CACHE_INSERT("");
118 : 9797 : split->memo = CACHE_INSERT("");
119 : 9797 : split->reconciled = NREC;
120 : 9797 : split->amount = gnc_numeric_zero();
121 : 9797 : split->value = gnc_numeric_zero();
122 : :
123 : 9797 : split->date_reconciled = 0;
124 : :
125 : 9797 : split->balance = gnc_numeric_zero();
126 : 9797 : split->cleared_balance = gnc_numeric_zero();
127 : 9797 : split->reconciled_balance = gnc_numeric_zero();
128 : 9797 : split->noclosing_balance = gnc_numeric_zero();
129 : :
130 : 9797 : split->gains = GAINS_STATUS_UNKNOWN;
131 : 9797 : split->gains_split = nullptr;
132 : 9797 : }
133 : :
134 : : static void
135 : 15211 : gnc_split_dispose(GObject *splitp)
136 : : {
137 : 15211 : G_OBJECT_CLASS(gnc_split_parent_class)->dispose(splitp);
138 : 15211 : }
139 : :
140 : : static void
141 : 7651 : gnc_split_finalize(GObject* splitp)
142 : : {
143 : 7651 : G_OBJECT_CLASS(gnc_split_parent_class)->finalize(splitp);
144 : 7651 : }
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 : 41 : gnc_split_class_init(SplitClass* klass)
302 : : {
303 : 41 : GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
304 : :
305 : 41 : gobject_class->dispose = gnc_split_dispose;
306 : 41 : gobject_class->finalize = gnc_split_finalize;
307 : 41 : gobject_class->set_property = gnc_split_set_property;
308 : 41 : gobject_class->get_property = gnc_split_get_property;
309 : :
310 : : g_object_class_install_property
311 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : (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 : 41 : }
488 : :
489 : : /********************************************************************\
490 : : * xaccInitSplit
491 : : * Initialize a Split structure
492 : : \********************************************************************/
493 : :
494 : : static void
495 : 7047 : xaccInitSplit(Split * split, QofBook *book)
496 : : {
497 : 7047 : qof_instance_init_data(&split->inst, GNC_ID_SPLIT, book);
498 : 7047 : }
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 : 7047 : xaccMallocSplit(QofBook *book)
533 : : {
534 : : Split *split;
535 : 7047 : g_return_val_if_fail (book, nullptr);
536 : :
537 : 7047 : split = GNC_SPLIT(g_object_new (GNC_TYPE_SPLIT, nullptr));
538 : 7047 : xaccInitSplit (split, book);
539 : :
540 : 7047 : 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 : 2724 : xaccDupeSplit (const Split *s)
554 : : {
555 : 2724 : 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 : 2724 : split->inst.e_type = nullptr;
562 : 2724 : qof_instance_copy_guid(split, s);
563 : 2724 : qof_instance_copy_book(split, s);
564 : :
565 : 2724 : split->parent = s->parent;
566 : 2724 : split->acc = s->acc;
567 : 2724 : split->orig_acc = s->orig_acc;
568 : 2724 : split->lot = s->lot;
569 : :
570 : 2724 : CACHE_REPLACE(split->memo, s->memo);
571 : 2724 : CACHE_REPLACE(split->action, s->action);
572 : :
573 : 2724 : qof_instance_copy_kvp (QOF_INSTANCE (split), QOF_INSTANCE (s));
574 : :
575 : 2724 : split->reconciled = s->reconciled;
576 : 2724 : split->date_reconciled = s->date_reconciled;
577 : :
578 : 2724 : split->value = s->value;
579 : 2724 : 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 : 2724 : 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 : 4839 : do_destroy (QofInstance *inst)
699 : : {
700 : 4839 : xaccFreeSplit (GNC_SPLIT (inst));
701 : 4839 : }
702 : :
703 : : void
704 : 7559 : xaccFreeSplit (Split *split)
705 : : {
706 : 7559 : if (!split) return;
707 : :
708 : : /* Debug double-free's */
709 : 7559 : if (((char *) 1) == split->memo)
710 : : {
711 : 0 : PERR ("double-free %p", split);
712 : 0 : return;
713 : : }
714 : 7559 : CACHE_REMOVE(split->memo);
715 : 7559 : CACHE_REMOVE(split->action);
716 : :
717 : 7559 : 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 : 4845 : if (GNC_IS_LOT (split->lot) && !qof_instance_get_destroying (QOF_INSTANCE (split->lot)))
721 : 0 : gnc_lot_remove_split (split->lot, split);
722 : 4845 : if (GNC_IS_ACCOUNT (split->acc)
723 : 4845 : && !qof_instance_get_destroying (QOF_INSTANCE (split->acc)))
724 : : {
725 : 4841 : 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 : 4841 : 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 : 7559 : split->memo = (char *) 1;
742 : 7559 : split->action = nullptr;
743 : 7559 : split->reconciled = NREC;
744 : 7559 : split->amount = gnc_numeric_zero();
745 : 7559 : split->value = gnc_numeric_zero();
746 : 7559 : split->parent = nullptr;
747 : 7559 : split->lot = nullptr;
748 : 7559 : split->acc = nullptr;
749 : 7559 : split->orig_acc = nullptr;
750 : :
751 : 7559 : split->date_reconciled = 0;
752 : 7559 : G_OBJECT_CLASS (QOF_INSTANCE_GET_CLASS (&split->inst))->dispose(G_OBJECT (split));
753 : :
754 : 7559 : 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 : 7559 : g_object_unref(split);
763 : : }
764 : :
765 : 30690 : void mark_split (Split *s)
766 : : {
767 : 30690 : if (s->acc)
768 : : {
769 : 21446 : g_object_set(s->acc, "sort-dirty", TRUE, "balance-dirty", TRUE, nullptr);
770 : : }
771 : :
772 : : /* set dirty flag on lot too. */
773 : 30690 : if (s->lot) gnc_lot_set_closed_unknown(s->lot);
774 : 30690 : }
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 : 507006 : xaccSplitGetAccount (const Split *s)
937 : : {
938 : 507006 : return s ? s->acc : nullptr;
939 : : }
940 : :
941 : : void
942 : 7024 : xaccSplitSetAccount (Split *s, Account *acc)
943 : : {
944 : : Transaction *trans;
945 : :
946 : 7024 : g_return_if_fail(s && acc);
947 : 7024 : g_return_if_fail(qof_instance_books_equal(acc, s));
948 : :
949 : 7024 : trans = s->parent;
950 : 7024 : if (trans)
951 : 5028 : xaccTransBeginEdit(trans);
952 : :
953 : 7024 : s->acc = acc;
954 : 7024 : qof_instance_set_dirty(QOF_INSTANCE(s));
955 : :
956 : 7024 : if (trans)
957 : 5028 : 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 : 12802 : xaccSplitCommitEdit(Split *s)
969 : : {
970 : 12802 : Account *acc = nullptr;
971 : 12802 : Account *orig_acc = nullptr;
972 : :
973 : 12802 : g_return_if_fail(s);
974 : 12802 : if (!qof_instance_is_dirty(QOF_INSTANCE(s)))
975 : 0 : return;
976 : :
977 : 12802 : orig_acc = s->orig_acc;
978 : :
979 : 12802 : if (GNC_IS_ACCOUNT(s->acc))
980 : 12784 : acc = s->acc;
981 : :
982 : : /* Remove from lot (but only if it hasn't been moved to
983 : : new lot already) */
984 : 12802 : 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 : 12802 : if (orig_acc && (orig_acc != acc || qof_instance_get_destroying(s)))
989 : : {
990 : 4956 : 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 : 12802 : if (acc && (orig_acc != acc) && !qof_instance_get_destroying(s))
998 : : {
999 : 6899 : 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 : 6898 : 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 : 6899 : xaccSplitSetAmount(s, xaccSplitGetAmount(s));
1011 : : }
1012 : :
1013 : 12802 : if (s->parent != s->orig_parent)
1014 : : {
1015 : : //FIXME: find better event
1016 : 6786 : if (s->orig_parent)
1017 : 2 : qof_event_gen(&s->orig_parent->inst, QOF_EVENT_MODIFY,
1018 : : nullptr);
1019 : : }
1020 : 12802 : if (s->lot)
1021 : : {
1022 : : /* A change of value/amnt affects gains display, etc. */
1023 : 259 : 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 : 12802 : s->orig_acc = s->acc;
1030 : 12802 : s->orig_parent = s->parent;
1031 : 12802 : if (!qof_commit_edit_part2(QOF_INSTANCE(s), commit_err, nullptr, do_destroy))
1032 : 0 : return;
1033 : :
1034 : 12802 : if (acc)
1035 : : {
1036 : 12784 : g_object_set(acc, "sort-dirty", TRUE, "balance-dirty", TRUE, nullptr);
1037 : 12784 : 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 : GValue v = G_VALUE_INIT;
1094 : 417 : GncGUID *guid = nullptr;
1095 : :
1096 : 417 : if (GAINS_STATUS_UNKNOWN != split->gains) return;
1097 : :
1098 : 290 : other = xaccSplitGetCapGainsSplit (split);
1099 : 290 : 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 : 290 : qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, "gains-source");
1107 : 290 : if (G_VALUE_HOLDS_BOXED (&v))
1108 : 1 : guid = (GncGUID*)g_value_get_boxed (&v);
1109 : 290 : if (!guid)
1110 : : {
1111 : : // CHECKME: We leave split->gains_split alone. Is that correct?
1112 : 289 : 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 : 290 : g_value_unset (&v);
1124 : : }
1125 : :
1126 : : /********************************************************************\
1127 : : \********************************************************************/
1128 : :
1129 : : static inline int
1130 : 14682 : get_currency_denom(const Split * s)
1131 : : {
1132 : 14682 : if (!(s && s->parent && s->parent->common_currency))
1133 : : {
1134 : 2799 : return GNC_DENOM_AUTO;
1135 : : }
1136 : : else
1137 : : {
1138 : 11883 : return gnc_commodity_get_fraction (s->parent->common_currency);
1139 : : }
1140 : : }
1141 : :
1142 : : static inline int
1143 : 12501 : get_commodity_denom(const Split * s)
1144 : : {
1145 : 12501 : if (!(s && s->acc))
1146 : : {
1147 : 2 : return GNC_DENOM_AUTO;
1148 : : }
1149 : : else
1150 : : {
1151 : 12499 : return xaccAccountGetCommoditySCU(s->acc);
1152 : : }
1153 : : }
1154 : :
1155 : : /********************************************************************\
1156 : : \********************************************************************/
1157 : :
1158 : : void
1159 : 2 : xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)
1160 : : {
1161 : 2 : if (!s) return;
1162 : 2 : ENTER (" ");
1163 : 2 : xaccTransBeginEdit (s->parent);
1164 : :
1165 : 2 : s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1166 : : GNC_HOW_RND_ROUND_HALF_UP);
1167 : 2 : s->value = gnc_numeric_mul(s->amount, price,
1168 : 2 : get_currency_denom(s), GNC_HOW_RND_ROUND_HALF_UP);
1169 : :
1170 : 2 : SET_GAINS_A_VDIRTY(s);
1171 : 2 : mark_split (s);
1172 : 2 : qof_instance_set_dirty(QOF_INSTANCE(s));
1173 : 2 : xaccTransCommitEdit(s->parent);
1174 : 2 : LEAVE ("");
1175 : : }
1176 : :
1177 : : static void
1178 : 0 : qofSplitSetSharePrice (Split *split, gnc_numeric price)
1179 : : {
1180 : 0 : g_return_if_fail(split);
1181 : 0 : split->value = gnc_numeric_mul(xaccSplitGetAmount(split),
1182 : 0 : price, get_currency_denom(split),
1183 : : GNC_HOW_RND_ROUND_HALF_UP);
1184 : : }
1185 : :
1186 : : void
1187 : 64 : xaccSplitSetSharePrice (Split *s, gnc_numeric price)
1188 : : {
1189 : 64 : if (!s) return;
1190 : :
1191 : 64 : if (gnc_numeric_zero_p (price))
1192 : 0 : return;
1193 : :
1194 : 64 : ENTER (" ");
1195 : 64 : xaccTransBeginEdit (s->parent);
1196 : :
1197 : 64 : s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
1198 : 64 : price, get_currency_denom(s),
1199 : : GNC_HOW_RND_ROUND_HALF_UP);
1200 : :
1201 : 64 : SET_GAINS_VDIRTY(s);
1202 : 64 : mark_split (s);
1203 : 64 : qof_instance_set_dirty(QOF_INSTANCE(s));
1204 : 64 : xaccTransCommitEdit(s->parent);
1205 : 64 : LEAVE ("");
1206 : : }
1207 : :
1208 : : static void
1209 : 0 : qofSplitSetAmount (Split *split, gnc_numeric amt)
1210 : : {
1211 : 0 : g_return_if_fail(split);
1212 : 0 : if (split->acc)
1213 : : {
1214 : 0 : split->amount = gnc_numeric_convert(amt,
1215 : 0 : get_commodity_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1216 : : }
1217 : : else
1218 : : {
1219 : 0 : split->amount = amt;
1220 : : }
1221 : : }
1222 : :
1223 : : /* The amount of the split in the _account's_ commodity. */
1224 : : void
1225 : 14127 : xaccSplitSetAmount (Split *s, gnc_numeric amt)
1226 : : {
1227 : 14127 : if (!s) return;
1228 : 14127 : g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1229 : 14127 : ENTER ("(split=%p) old amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1230 : : " new amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1231 : : s->amount.num, s->amount.denom, amt.num, amt.denom);
1232 : :
1233 : 14127 : xaccTransBeginEdit (s->parent);
1234 : 14127 : if (s->acc)
1235 : : {
1236 : 12364 : s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
1237 : : GNC_HOW_RND_ROUND_HALF_UP);
1238 : 12364 : g_assert (gnc_numeric_check (s->amount) == GNC_ERROR_OK);
1239 : : }
1240 : : else
1241 : 1763 : s->amount = amt;
1242 : :
1243 : 14127 : SET_GAINS_ADIRTY(s);
1244 : 14127 : mark_split (s);
1245 : 14127 : qof_instance_set_dirty(QOF_INSTANCE(s));
1246 : 14127 : xaccTransCommitEdit(s->parent);
1247 : 14127 : LEAVE("");
1248 : : }
1249 : :
1250 : : static void
1251 : 0 : qofSplitSetValue (Split *split, gnc_numeric amt)
1252 : : {
1253 : 0 : g_return_if_fail(split);
1254 : 0 : split->value = gnc_numeric_convert(amt,
1255 : 0 : get_currency_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
1256 : 0 : g_assert(gnc_numeric_check (split->value) != GNC_ERROR_OK);
1257 : : }
1258 : :
1259 : : /* The value of the split in the _transaction's_ currency. */
1260 : : void
1261 : 14474 : xaccSplitSetValue (Split *s, gnc_numeric amt)
1262 : : {
1263 : : gnc_numeric new_val;
1264 : 14474 : if (!s) return;
1265 : :
1266 : 14474 : g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
1267 : 14474 : ENTER ("(split=%p) old val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
1268 : : " new val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
1269 : : s->value.num, s->value.denom, amt.num, amt.denom);
1270 : :
1271 : 14474 : xaccTransBeginEdit (s->parent);
1272 : 14474 : new_val = gnc_numeric_convert(amt, get_currency_denom(s),
1273 : : GNC_HOW_RND_ROUND_HALF_UP);
1274 : 28948 : if (gnc_numeric_check(new_val) == GNC_ERROR_OK &&
1275 : 14474 : !(gnc_numeric_zero_p (new_val) && !gnc_numeric_zero_p (amt)))
1276 : : {
1277 : 14468 : s->value = new_val;
1278 : : }
1279 : : else
1280 : : {
1281 : 6 : PERR("numeric error %s in converting the split value's denominator with amount %s and denom %d",
1282 : : gnc_numeric_errorCode_to_string(gnc_numeric_check(new_val)),
1283 : : gnc_num_dbg_to_string (amt), get_currency_denom(s));
1284 : : }
1285 : :
1286 : 14474 : SET_GAINS_VDIRTY(s);
1287 : 14474 : mark_split (s);
1288 : 14474 : qof_instance_set_dirty(QOF_INSTANCE(s));
1289 : 14474 : xaccTransCommitEdit(s->parent);
1290 : 14474 : LEAVE ("");
1291 : : }
1292 : :
1293 : : /********************************************************************\
1294 : : \********************************************************************/
1295 : :
1296 : : gnc_numeric
1297 : 1862 : xaccSplitGetBalance (const Split *s)
1298 : : {
1299 : 1862 : return s ? s->balance : gnc_numeric_zero();
1300 : : }
1301 : :
1302 : : gnc_numeric
1303 : 10319 : xaccSplitGetNoclosingBalance (const Split *s)
1304 : : {
1305 : 10319 : return s ? s->noclosing_balance : gnc_numeric_zero();
1306 : : }
1307 : :
1308 : : gnc_numeric
1309 : 0 : xaccSplitGetClearedBalance (const Split *s)
1310 : : {
1311 : 0 : return s ? s->cleared_balance : gnc_numeric_zero();
1312 : : }
1313 : :
1314 : : gnc_numeric
1315 : 0 : xaccSplitGetReconciledBalance (const Split *s)
1316 : : {
1317 : 0 : return s ? s->reconciled_balance : gnc_numeric_zero();
1318 : : }
1319 : :
1320 : : void
1321 : 135 : xaccSplitSetBaseValue (Split *s, gnc_numeric value,
1322 : : const gnc_commodity * base_currency)
1323 : : {
1324 : : const gnc_commodity *currency;
1325 : : const gnc_commodity *commodity;
1326 : :
1327 : 135 : if (!s) return;
1328 : 135 : xaccTransBeginEdit (s->parent);
1329 : :
1330 : 135 : if (!s->acc)
1331 : : {
1332 : 1 : PERR ("split must have a parent account");
1333 : 1 : return;
1334 : : }
1335 : :
1336 : 134 : currency = xaccTransGetCurrency (s->parent);
1337 : 134 : commodity = xaccAccountGetCommodity (s->acc);
1338 : :
1339 : : /* If the base_currency is the transaction's commodity ('currency'),
1340 : : * set the value. If it's the account commodity, set the
1341 : : * amount. If both, set both. */
1342 : 134 : if (gnc_commodity_equiv(currency, base_currency))
1343 : : {
1344 : 132 : if (gnc_commodity_equiv(commodity, base_currency))
1345 : : {
1346 : 131 : s->amount = gnc_numeric_convert(value,
1347 : 131 : get_commodity_denom(s),
1348 : : GNC_HOW_RND_ROUND_HALF_UP);
1349 : : }
1350 : 132 : s->value = gnc_numeric_convert(value,
1351 : 132 : get_currency_denom(s),
1352 : : GNC_HOW_RND_ROUND_HALF_UP);
1353 : : }
1354 : 2 : else if (gnc_commodity_equiv(commodity, base_currency))
1355 : : {
1356 : 1 : s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
1357 : : GNC_HOW_RND_ROUND_HALF_UP);
1358 : : }
1359 : : else
1360 : : {
1361 : 1 : PERR ("inappropriate base currency %s "
1362 : : "given split currency=%s and commodity=%s\n",
1363 : : gnc_commodity_get_printname(base_currency),
1364 : : gnc_commodity_get_printname(currency),
1365 : : gnc_commodity_get_printname(commodity));
1366 : 1 : return;
1367 : : }
1368 : :
1369 : 133 : SET_GAINS_A_VDIRTY(s);
1370 : 133 : mark_split (s);
1371 : 133 : qof_instance_set_dirty(QOF_INSTANCE(s));
1372 : 133 : xaccTransCommitEdit(s->parent);
1373 : : }
1374 : :
1375 : : gnc_numeric
1376 : 0 : xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)
1377 : : {
1378 : 0 : if (!s || !s->acc || !s->parent) return gnc_numeric_zero();
1379 : :
1380 : : /* be more precise -- the value depends on the currency we want it
1381 : : * expressed in. */
1382 : 0 : if (gnc_commodity_equiv(xaccTransGetCurrency(s->parent), base_currency))
1383 : 0 : return xaccSplitGetValue(s);
1384 : 0 : if (gnc_commodity_equiv(xaccAccountGetCommodity(s->acc), base_currency))
1385 : 0 : return xaccSplitGetAmount(s);
1386 : :
1387 : 0 : PERR ("inappropriate base currency %s "
1388 : : "given split currency=%s and commodity=%s\n",
1389 : : gnc_commodity_get_printname(base_currency),
1390 : : gnc_commodity_get_printname(xaccTransGetCurrency (s->parent)),
1391 : : gnc_commodity_get_printname(xaccAccountGetCommodity(s->acc)));
1392 : 0 : return gnc_numeric_zero();
1393 : : }
1394 : :
1395 : : /********************************************************************\
1396 : : \********************************************************************/
1397 : :
1398 : : gnc_numeric
1399 : 154 : xaccSplitConvertAmount (const Split *split, const Account * account)
1400 : : {
1401 : : gnc_commodity *acc_com, *to_commodity;
1402 : : Transaction *txn;
1403 : : gnc_numeric amount, value, convrate;
1404 : : Account * split_acc;
1405 : :
1406 : 154 : amount = xaccSplitGetAmount (split);
1407 : :
1408 : : /* If this split is attached to this account, OR */
1409 : 154 : split_acc = xaccSplitGetAccount (split);
1410 : 154 : if (split_acc == account)
1411 : 105 : return amount;
1412 : :
1413 : : /* If split->account->commodity == to_commodity, return the amount */
1414 : 49 : acc_com = xaccAccountGetCommodity (split_acc);
1415 : 49 : to_commodity = xaccAccountGetCommodity (account);
1416 : 49 : if (acc_com && gnc_commodity_equal (acc_com, to_commodity))
1417 : 45 : return amount;
1418 : :
1419 : : /* Ok, this split is not for the viewed account, and the commodity
1420 : : * does not match. So we need to do some conversion.
1421 : : *
1422 : : * First, we can cheat. If this transaction is balanced and has
1423 : : * exactly two splits, then we can implicitly determine the exchange
1424 : : * rate and just return the 'other' split amount.
1425 : : */
1426 : 4 : txn = xaccSplitGetParent (split);
1427 : 4 : if (txn && xaccTransIsBalanced (txn))
1428 : : {
1429 : 2 : const Split *osplit = xaccSplitGetOtherSplit (split);
1430 : :
1431 : 2 : if (osplit)
1432 : : {
1433 : : gnc_commodity* split_comm =
1434 : 2 : xaccAccountGetCommodity(xaccSplitGetAccount(osplit));
1435 : 2 : if (!gnc_commodity_equal(to_commodity, split_comm))
1436 : : {
1437 : : gchar guidstr[GUID_ENCODING_LENGTH+1];
1438 : 1 : guid_to_string_buff(xaccSplitGetGUID(osplit),guidstr);
1439 : 1 : PERR("The split's (%s) amount can't be converted from %s into %s.",
1440 : : guidstr,
1441 : : gnc_commodity_get_mnemonic(split_comm),
1442 : : gnc_commodity_get_mnemonic(to_commodity)
1443 : : );
1444 : 1 : return gnc_numeric_zero();
1445 : : }
1446 : 1 : return gnc_numeric_neg (xaccSplitGetAmount (osplit));
1447 : : }
1448 : : }
1449 : :
1450 : : /* ... otherwise, we need to compute the amount from the conversion
1451 : : * rate into _this account_. So, find the split into this account,
1452 : : * compute the conversion rate (based on amount/value), and then multiply
1453 : : * this times the split value.
1454 : : */
1455 : 2 : value = xaccSplitGetValue (split);
1456 : :
1457 : 2 : if (gnc_numeric_zero_p (value))
1458 : : {
1459 : 1 : return value;
1460 : : }
1461 : :
1462 : 1 : convrate = xaccTransGetAccountConvRate(txn, account);
1463 : 1 : return gnc_numeric_mul (value, convrate,
1464 : 1 : gnc_commodity_get_fraction (to_commodity),
1465 : 1 : GNC_HOW_RND_ROUND_HALF_UP);
1466 : : }
1467 : :
1468 : : /********************************************************************\
1469 : : \********************************************************************/
1470 : :
1471 : : gboolean
1472 : 4851 : xaccSplitDestroy (Split *split)
1473 : : {
1474 : : Account *acc;
1475 : : Transaction *trans;
1476 : : GncEventData ed;
1477 : :
1478 : 4851 : if (!split) return TRUE;
1479 : :
1480 : 4851 : acc = split->acc;
1481 : 4851 : trans = split->parent;
1482 : 4851 : if (acc && !qof_instance_get_destroying(acc)
1483 : 4838 : && !qof_instance_get_destroying(trans)
1484 : 9702 : && xaccTransGetReadOnly(trans))
1485 : 0 : return FALSE;
1486 : :
1487 : 4851 : xaccTransBeginEdit(trans);
1488 : 4851 : ed.node = split;
1489 : 4851 : ed.idx = xaccTransGetSplitIndex(trans, split);
1490 : 4851 : qof_instance_set_dirty(QOF_INSTANCE(split));
1491 : 4851 : qof_instance_set_destroying(split, TRUE);
1492 : 4851 : qof_event_gen(&trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1493 : 4851 : xaccTransCommitEdit(trans);
1494 : :
1495 : 4851 : return TRUE;
1496 : : }
1497 : :
1498 : : /********************************************************************\
1499 : : \********************************************************************/
1500 : :
1501 : : gint
1502 : 652534 : xaccSplitOrder (const Split *sa, const Split *sb)
1503 : : {
1504 : : int retval;
1505 : : int comp;
1506 : : const char *da, *db;
1507 : : gboolean action_for_num;
1508 : :
1509 : 652534 : if (sa == sb) return 0;
1510 : : /* nothing is always less than something */
1511 : 652533 : if (!sa) return -1;
1512 : 652532 : if (!sb) return +1;
1513 : :
1514 : : /* sort in transaction order, but use split action rather than trans num
1515 : : * according to book option */
1516 : : action_for_num = qof_book_use_split_action_for_num_field
1517 : 652531 : (xaccSplitGetBook (sa));
1518 : 652531 : if (action_for_num)
1519 : 2 : retval = xaccTransOrder_num_action (sa->parent, sa->action,
1520 : 2 : sb->parent, sb->action);
1521 : : else
1522 : 652529 : retval = xaccTransOrder (sa->parent, sb->parent);
1523 : 652531 : if (retval) return retval;
1524 : :
1525 : : /* otherwise, sort on memo strings */
1526 : 11033 : da = sa->memo ? sa->memo : "";
1527 : 11033 : db = sb->memo ? sb->memo : "";
1528 : 11033 : retval = g_utf8_collate (da, db);
1529 : 11033 : if (retval)
1530 : 138 : return retval;
1531 : :
1532 : : /* otherwise, sort on action strings */
1533 : 10895 : da = sa->action ? sa->action : "";
1534 : 10895 : db = sb->action ? sb->action : "";
1535 : 10895 : retval = g_utf8_collate (da, db);
1536 : 10895 : if (retval != 0)
1537 : 570 : return retval;
1538 : :
1539 : : /* the reconciled flag ... */
1540 : 10325 : if (sa->reconciled < sb->reconciled) return -1;
1541 : 10324 : if (sa->reconciled > sb->reconciled) return +1;
1542 : :
1543 : : /* compare amounts */
1544 : 10323 : comp = gnc_numeric_compare(xaccSplitGetAmount(sa), xaccSplitGetAmount (sb));
1545 : 10323 : if (comp < 0) return -1;
1546 : 5944 : if (comp > 0) return +1;
1547 : :
1548 : 278 : comp = gnc_numeric_compare(xaccSplitGetValue(sa), xaccSplitGetValue (sb));
1549 : 278 : if (comp < 0) return -1;
1550 : 275 : if (comp > 0) return +1;
1551 : :
1552 : : /* if dates differ, return */
1553 : 272 : if (sa->date_reconciled < sb->date_reconciled)
1554 : 1 : return -1;
1555 : 271 : else if (sa->date_reconciled > sb->date_reconciled)
1556 : 2 : return 1;
1557 : :
1558 : : /* else, sort on guid - keeps sort stable. */
1559 : 269 : retval = qof_instance_guid_compare(sa, sb);
1560 : 269 : if (retval) return retval;
1561 : :
1562 : 0 : return 0;
1563 : : }
1564 : :
1565 : : gint
1566 : 192 : xaccSplitOrderDateOnly (const Split *sa, const Split *sb)
1567 : : {
1568 : : Transaction *ta, *tb;
1569 : :
1570 : 192 : if (sa == sb) return 0;
1571 : : /* nothing is always less than something */
1572 : 191 : if (!sa) return -1;
1573 : 190 : if (!sb) return +1;
1574 : :
1575 : 189 : ta = sa->parent;
1576 : 189 : tb = sb->parent;
1577 : 189 : if ( !ta && !tb ) return 0;
1578 : 188 : if ( !tb ) return -1;
1579 : 187 : if ( !ta ) return +1;
1580 : :
1581 : 186 : if (ta->date_posted == tb->date_posted)
1582 : 87 : return -1; // Keep the same order
1583 : 99 : return (ta->date_posted > tb->date_posted) - (ta->date_posted < tb->date_posted);
1584 : : }
1585 : :
1586 : : static gboolean
1587 : 30 : get_corr_account_split(const Split *sa, const Split **retval)
1588 : : {
1589 : 30 : *retval = nullptr;
1590 : 30 : g_return_val_if_fail(sa, FALSE);
1591 : :
1592 : 29 : if (xaccTransCountSplits (sa->parent) > 2)
1593 : 2 : return FALSE;
1594 : :
1595 : 27 : *retval = xaccSplitGetOtherSplit (sa);
1596 : 27 : if (*retval)
1597 : 24 : return TRUE;
1598 : : else
1599 : 3 : return FALSE;
1600 : : }
1601 : :
1602 : : /* TODO: these static consts can be shared. */
1603 : : const char *
1604 : 0 : xaccSplitGetCorrAccountName(const Split *sa)
1605 : : {
1606 : : static const char *split_const = nullptr;
1607 : : const Split *other_split;
1608 : :
1609 : 0 : if (!get_corr_account_split(sa, &other_split))
1610 : : {
1611 : 0 : if (!split_const)
1612 : 0 : split_const = _("-- Split Transaction --");
1613 : :
1614 : 0 : return split_const;
1615 : : }
1616 : :
1617 : 0 : return xaccAccountGetName(other_split->acc);
1618 : : }
1619 : :
1620 : : char *
1621 : 21 : xaccSplitGetCorrAccountFullName(const Split *sa)
1622 : : {
1623 : : static const char *split_const = nullptr;
1624 : : const Split *other_split;
1625 : :
1626 : 21 : if (!get_corr_account_split(sa, &other_split))
1627 : : {
1628 : 1 : if (!split_const)
1629 : 1 : split_const = _("-- Split Transaction --");
1630 : :
1631 : 2 : return g_strdup(split_const);
1632 : : }
1633 : 20 : return gnc_account_get_full_name(other_split->acc);
1634 : : }
1635 : :
1636 : : const char *
1637 : 4 : xaccSplitGetCorrAccountCode(const Split *sa)
1638 : : {
1639 : : static const char *split_const = nullptr;
1640 : : const Split *other_split;
1641 : :
1642 : 4 : if (!get_corr_account_split(sa, &other_split))
1643 : : {
1644 : 1 : if (!split_const)
1645 : 1 : split_const = C_("Displayed account code of the other account in a multi-split transaction", "Split");
1646 : :
1647 : 1 : return split_const;
1648 : : }
1649 : 3 : return xaccAccountGetCode(other_split->acc);
1650 : : }
1651 : :
1652 : : /* TODO: It's not too hard to make this function avoid the malloc/free. */
1653 : : int
1654 : 1552 : xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
1655 : : {
1656 : : Account *aa, *ab;
1657 : 1552 : if (sa == sb) return 0;
1658 : 1551 : if (!sa) return -1;
1659 : 1550 : if (!sb) return 1;
1660 : :
1661 : 1549 : aa = sa->acc;
1662 : 1549 : ab = sb->acc;
1663 : 1549 : if (aa == ab) return 0;
1664 : :
1665 : 96 : auto path_a = gnc_account_get_all_parents (aa);
1666 : 96 : auto path_b = gnc_account_get_all_parents (ab);
1667 : 96 : auto mismatch_pair = std::mismatch (path_a.rbegin(), path_a.rend(),
1668 : 192 : path_b.rbegin(), path_b.rend());
1669 : :
1670 : 192 : return mismatch_pair.first == path_a.rend() ? -1
1671 : 96 : : mismatch_pair.second == path_b.rend() ? 1
1672 : 96 : : g_utf8_collate (xaccAccountGetName (*mismatch_pair.first),
1673 : 96 : xaccAccountGetName (*mismatch_pair.second));
1674 : 0 : }
1675 : :
1676 : :
1677 : : int
1678 : 4 : xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
1679 : : {
1680 : : Account *aa, *ab;
1681 : 4 : if (!sa && !sb) return 0;
1682 : 3 : if (!sa) return -1;
1683 : 2 : if (!sb) return 1;
1684 : :
1685 : 1 : aa = sa->acc;
1686 : 1 : ab = sb->acc;
1687 : :
1688 : 1 : return g_strcmp0(xaccAccountGetCode(aa), xaccAccountGetCode(ab));
1689 : : }
1690 : :
1691 : : int
1692 : 11 : xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
1693 : : {
1694 : : char *ca, *cb;
1695 : : int retval;
1696 : 11 : if (!sa && !sb) return 0;
1697 : 10 : if (!sa) return -1;
1698 : 9 : if (!sb) return 1;
1699 : :
1700 : : /* doesn't matter what separator we use
1701 : : * as long as they are the same
1702 : : */
1703 : :
1704 : 8 : ca = xaccSplitGetCorrAccountFullName(sa);
1705 : 8 : cb = xaccSplitGetCorrAccountFullName(sb);
1706 : 8 : retval = g_strcmp0(ca, cb);
1707 : 8 : g_free(ca);
1708 : 8 : g_free(cb);
1709 : 8 : return retval;
1710 : : }
1711 : :
1712 : : int
1713 : 4 : xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
1714 : : {
1715 : : const char *ca, *cb;
1716 : 4 : if (!sa && !sb) return 0;
1717 : 3 : if (!sa) return -1;
1718 : 2 : if (!sb) return 1;
1719 : :
1720 : 1 : ca = xaccSplitGetCorrAccountCode(sa);
1721 : 1 : cb = xaccSplitGetCorrAccountCode(sb);
1722 : 1 : return g_strcmp0(ca, cb);
1723 : : }
1724 : :
1725 : : static void
1726 : 0 : qofSplitSetMemo (Split *split, const char* memo)
1727 : : {
1728 : 0 : g_return_if_fail(split);
1729 : 0 : CACHE_REPLACE(split->memo, memo);
1730 : : }
1731 : :
1732 : : void
1733 : 1767 : xaccSplitSetMemo (Split *split, const char *memo)
1734 : : {
1735 : 1767 : if (!split || !memo) return;
1736 : 1666 : xaccTransBeginEdit (split->parent);
1737 : :
1738 : 1666 : CACHE_REPLACE(split->memo, memo);
1739 : 1666 : qof_instance_set_dirty(QOF_INSTANCE(split));
1740 : 1666 : xaccTransCommitEdit(split->parent);
1741 : :
1742 : : }
1743 : :
1744 : : static void
1745 : 0 : qofSplitSetAction (Split *split, const char *actn)
1746 : : {
1747 : 0 : g_return_if_fail(split);
1748 : 0 : CACHE_REPLACE(split->action, actn);
1749 : : }
1750 : :
1751 : : void
1752 : 1038 : xaccSplitSetAction (Split *split, const char *actn)
1753 : : {
1754 : 1038 : if (!split || !actn) return;
1755 : 1038 : xaccTransBeginEdit (split->parent);
1756 : :
1757 : 1038 : CACHE_REPLACE(split->action, actn);
1758 : 1038 : qof_instance_set_dirty(QOF_INSTANCE(split));
1759 : 1038 : xaccTransCommitEdit(split->parent);
1760 : :
1761 : : }
1762 : :
1763 : : static void
1764 : 0 : qofSplitSetReconcile (Split *split, char recn)
1765 : : {
1766 : 0 : g_return_if_fail(split);
1767 : 0 : switch (recn)
1768 : : {
1769 : 0 : case NREC:
1770 : : case CREC:
1771 : : case YREC:
1772 : : case FREC:
1773 : : case VREC:
1774 : 0 : split->reconciled = recn;
1775 : 0 : mark_split (split);
1776 : 0 : xaccAccountRecomputeBalance (split->acc);
1777 : 0 : break;
1778 : 0 : default:
1779 : 0 : PERR("Bad reconciled flag");
1780 : 0 : break;
1781 : : }
1782 : : }
1783 : :
1784 : : void
1785 : 2835 : xaccSplitSetReconcile (Split *split, char recn)
1786 : : {
1787 : 2835 : if (!split || split->reconciled == recn) return;
1788 : 1110 : xaccTransBeginEdit (split->parent);
1789 : :
1790 : 1110 : switch (recn)
1791 : : {
1792 : 1110 : case NREC:
1793 : : case CREC:
1794 : : case YREC:
1795 : : case FREC:
1796 : : case VREC:
1797 : 1110 : split->reconciled = recn;
1798 : 1110 : mark_split (split);
1799 : 1110 : qof_instance_set_dirty(QOF_INSTANCE(split));
1800 : 1110 : xaccAccountRecomputeBalance (split->acc);
1801 : 1110 : break;
1802 : 0 : default:
1803 : 0 : PERR("Bad reconciled flag");
1804 : 0 : break;
1805 : : }
1806 : 1110 : xaccTransCommitEdit(split->parent);
1807 : :
1808 : : }
1809 : :
1810 : : void
1811 : 783 : xaccSplitSetDateReconciledSecs (Split *split, time64 secs)
1812 : : {
1813 : 783 : if (!split) return;
1814 : 783 : xaccTransBeginEdit (split->parent);
1815 : :
1816 : 783 : split->date_reconciled = secs;
1817 : 783 : qof_instance_set_dirty(QOF_INSTANCE(split));
1818 : 783 : xaccTransCommitEdit(split->parent);
1819 : :
1820 : : }
1821 : :
1822 : :
1823 : : /*################## Added for Reg2 #################*/
1824 : : time64
1825 : 147 : xaccSplitGetDateReconciled (const Split * split)
1826 : : {
1827 : 147 : return split ? split->date_reconciled : 0;
1828 : : }
1829 : : /*################## Added for Reg2 #################*/
1830 : :
1831 : : /********************************************************************\
1832 : : \********************************************************************/
1833 : :
1834 : : /* return the parent transaction of the split */
1835 : : Transaction *
1836 : 984993 : xaccSplitGetParent (const Split *split)
1837 : : {
1838 : 984993 : return split ? split->parent : nullptr;
1839 : : }
1840 : :
1841 : : void
1842 : 6977 : xaccSplitSetParent(Split *s, Transaction *t)
1843 : : {
1844 : : Transaction *old_trans;
1845 : : GncEventData ed;
1846 : :
1847 : 6979 : g_return_if_fail(s);
1848 : 6977 : if (s->parent == t) return;
1849 : :
1850 : 6975 : if (s->parent != s->orig_parent && s->orig_parent != t)
1851 : 1 : PERR("You may not add the split to more than one transaction"
1852 : : " during the BeginEdit/CommitEdit block.");
1853 : 6975 : xaccTransBeginEdit(t);
1854 : 6975 : old_trans = s->parent;
1855 : :
1856 : 6975 : xaccTransBeginEdit(old_trans);
1857 : :
1858 : 6975 : ed.node = s;
1859 : 6975 : if (old_trans)
1860 : : {
1861 : 11 : ed.idx = xaccTransGetSplitIndex(old_trans, s);
1862 : 11 : qof_event_gen(&old_trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
1863 : : }
1864 : 6975 : s->parent = t;
1865 : :
1866 : 6975 : xaccTransCommitEdit(old_trans);
1867 : 6975 : qof_instance_set_dirty(QOF_INSTANCE(s));
1868 : :
1869 : 6975 : if (t)
1870 : : {
1871 : : /* Convert split to new transaction's commodity denominator */
1872 : 6967 : xaccSplitSetValue(s, xaccSplitGetValue(s));
1873 : :
1874 : : /* add ourselves to the new transaction's list of pending splits. */
1875 : 6967 : if (nullptr == g_list_find(t->splits, s))
1876 : 6966 : t->splits = g_list_append(t->splits, s);
1877 : :
1878 : 6967 : ed.idx = -1; /* unused */
1879 : 6967 : qof_event_gen(&t->inst, GNC_EVENT_ITEM_ADDED, &ed);
1880 : : }
1881 : 6975 : xaccTransCommitEdit(t);
1882 : : }
1883 : :
1884 : :
1885 : : GNCLot *
1886 : 590 : xaccSplitGetLot (const Split *split)
1887 : : {
1888 : 590 : return split ? split->lot : nullptr;
1889 : : }
1890 : :
1891 : : void
1892 : 255 : xaccSplitSetLot(Split* split, GNCLot* lot)
1893 : : {
1894 : 255 : xaccTransBeginEdit (split->parent);
1895 : 255 : split->lot = lot;
1896 : 255 : qof_instance_set_dirty(QOF_INSTANCE(split));
1897 : 255 : xaccTransCommitEdit(split->parent);
1898 : 255 : }
1899 : :
1900 : : const char *
1901 : 2787 : xaccSplitGetMemo (const Split *split)
1902 : : {
1903 : 2787 : return split ? split->memo : nullptr;
1904 : : }
1905 : :
1906 : : const char *
1907 : 1537 : xaccSplitGetAction (const Split *split)
1908 : : {
1909 : 1537 : return split ? split->action : nullptr;
1910 : : }
1911 : :
1912 : : char
1913 : 369002 : xaccSplitGetReconcile (const Split *split)
1914 : : {
1915 : 369002 : return split ? split->reconciled : ' ';
1916 : : }
1917 : :
1918 : :
1919 : : gnc_numeric
1920 : 212339 : xaccSplitGetAmount (const Split * split)
1921 : : {
1922 : 212339 : return split ? split->amount : gnc_numeric_zero();
1923 : : }
1924 : :
1925 : : gnc_numeric
1926 : 67650 : xaccSplitGetValue (const Split * split)
1927 : : {
1928 : 67650 : return split ? split->value : gnc_numeric_zero();
1929 : : }
1930 : :
1931 : : gnc_numeric
1932 : 562 : xaccSplitGetSharePrice (const Split * split)
1933 : : {
1934 : : gnc_numeric amt, val, price;
1935 : 562 : if (!split) return gnc_numeric_create(0, 1);
1936 : :
1937 : :
1938 : : /* if amount == 0, return 0
1939 : : * otherwise return value/amount
1940 : : */
1941 : :
1942 : 561 : amt = xaccSplitGetAmount(split);
1943 : 561 : val = xaccSplitGetValue(split);
1944 : 561 : if (gnc_numeric_zero_p(amt))
1945 : 48 : return gnc_numeric_create(0, 1);
1946 : :
1947 : 513 : price = gnc_numeric_div(val, amt,
1948 : : GNC_DENOM_AUTO,
1949 : : GNC_HOW_RND_ROUND_HALF_UP);
1950 : :
1951 : : /* During random checks we can get some very weird prices. Let's
1952 : : * handle some overflow and other error conditions by returning
1953 : : * zero. But still print an error to let us know it happened.
1954 : : */
1955 : 513 : if (gnc_numeric_check(price))
1956 : : {
1957 : 2 : PERR("Computing share price failed (%d): [ %" G_GINT64_FORMAT " / %"
1958 : : G_GINT64_FORMAT " ] / [ %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " ]",
1959 : : gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
1960 : 2 : return gnc_numeric_create(0, 1);
1961 : : }
1962 : :
1963 : 511 : return price;
1964 : : }
1965 : :
1966 : : /********************************************************************\
1967 : : \********************************************************************/
1968 : :
1969 : : QofBook *
1970 : 917734 : xaccSplitGetBook (const Split *split)
1971 : : {
1972 : 917734 : return qof_instance_get_book(QOF_INSTANCE(split));
1973 : : }
1974 : :
1975 : : const char *
1976 : 28 : xaccSplitGetType(const Split *s)
1977 : : {
1978 : 28 : if (!s) return nullptr;
1979 : :
1980 : 28 : GValue v = G_VALUE_INIT;
1981 : : const char* type;
1982 : 28 : qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
1983 : 28 : type = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : nullptr;
1984 : : const char *rv;
1985 : 28 : if (!type || !g_strcmp0 (type, split_type_normal))
1986 : 27 : rv = split_type_normal;
1987 : 1 : else if (!g_strcmp0 (type, split_type_stock_split))
1988 : 1 : rv = split_type_stock_split;
1989 : : else
1990 : : {
1991 : 0 : PERR ("unexpected split-type %s, reset to normal.", type);
1992 : 0 : rv = split_type_normal;
1993 : : }
1994 : 28 : g_value_unset (&v);
1995 : 28 : return rv;
1996 : : }
1997 : :
1998 : : /* reconfigure a split to be a stock split - after this, you shouldn't
1999 : : mess with the value, just the amount. */
2000 : : void
2001 : 11 : xaccSplitMakeStockSplit(Split *s)
2002 : : {
2003 : 11 : GValue v = G_VALUE_INIT;
2004 : 11 : xaccTransBeginEdit (s->parent);
2005 : :
2006 : 11 : s->value = gnc_numeric_zero();
2007 : 11 : g_value_init (&v, G_TYPE_STRING);
2008 : 11 : g_value_set_static_string (&v, split_type_stock_split);
2009 : 11 : qof_instance_set_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
2010 : 11 : SET_GAINS_VDIRTY(s);
2011 : 11 : mark_split(s);
2012 : 11 : qof_instance_set_dirty(QOF_INSTANCE(s));
2013 : 11 : xaccTransCommitEdit(s->parent);
2014 : 11 : g_value_unset (&v);
2015 : 11 : }
2016 : :
2017 : : void
2018 : 8 : xaccSplitAddPeerSplit (Split *split, const Split *other_split,
2019 : : time64 timestamp)
2020 : : {
2021 : : const GncGUID* guid;
2022 : :
2023 : 8 : g_return_if_fail (split != nullptr);
2024 : 8 : g_return_if_fail (other_split != nullptr);
2025 : :
2026 : 8 : guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2027 : 8 : xaccTransBeginEdit (split->parent);
2028 : 8 : qof_instance_kvp_add_guid (QOF_INSTANCE (split), "lot-split",
2029 : 8 : gnc_time(nullptr), "peer_guid", guid_copy(guid));
2030 : 8 : mark_split (split);
2031 : 8 : qof_instance_set_dirty (QOF_INSTANCE (split));
2032 : 8 : xaccTransCommitEdit (split->parent);
2033 : : }
2034 : :
2035 : : gboolean
2036 : 110 : xaccSplitHasPeers (const Split *split)
2037 : : {
2038 : 110 : return qof_instance_has_slot (QOF_INSTANCE (split), "lot-split");
2039 : : }
2040 : :
2041 : : gboolean
2042 : 1 : xaccSplitIsPeerSplit (const Split *split, const Split *other_split)
2043 : : {
2044 : : const GncGUID* guid;
2045 : :
2046 : 1 : g_return_val_if_fail (split != nullptr, FALSE);
2047 : 1 : g_return_val_if_fail (other_split != nullptr, FALSE);
2048 : :
2049 : 1 : guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2050 : 1 : return qof_instance_kvp_has_guid (QOF_INSTANCE (split), "lot-split",
2051 : 1 : "peer_guid", guid);
2052 : : }
2053 : :
2054 : : void
2055 : 0 : xaccSplitRemovePeerSplit (Split *split, const Split *other_split)
2056 : : {
2057 : : const GncGUID* guid;
2058 : :
2059 : 0 : g_return_if_fail (split != nullptr);
2060 : 0 : g_return_if_fail (other_split != nullptr);
2061 : :
2062 : 0 : guid = qof_instance_get_guid (QOF_INSTANCE (other_split));
2063 : 0 : xaccTransBeginEdit (split->parent);
2064 : 0 : qof_instance_kvp_remove_guid (QOF_INSTANCE (split), "lot-split",
2065 : : "peer_guid", guid);
2066 : 0 : mark_split (split);
2067 : 0 : qof_instance_set_dirty (QOF_INSTANCE (split));
2068 : 0 : xaccTransCommitEdit (split->parent);
2069 : : }
2070 : :
2071 : : void
2072 : 0 : xaccSplitMergePeerSplits (Split *split, const Split *other_split)
2073 : : {
2074 : 0 : xaccTransBeginEdit (split->parent);
2075 : 0 : qof_instance_kvp_merge_guids (QOF_INSTANCE (split),
2076 : 0 : QOF_INSTANCE (other_split), "lot-split");
2077 : 0 : mark_split (split);
2078 : 0 : qof_instance_set_dirty (QOF_INSTANCE (split));
2079 : 0 : xaccTransCommitEdit (split->parent);
2080 : 0 : }
2081 : :
2082 : : /********************************************************************\
2083 : : \********************************************************************/
2084 : : /* In the old world, the 'other split' was the other split of a
2085 : : * transaction that contained only two splits. In the new world,
2086 : : * a split may have been cut up between multiple lots, although
2087 : : * in a conceptual sense, if lots hadn't been used, there would be
2088 : : * only a pair. So we handle this conceptual case: we can still
2089 : : * identify, unambiguously, the 'other' split when 'this' split
2090 : : * as been cut up across lots. We do this by looking for the
2091 : : * 'lot-split' keyword, which occurs only in cut-up splits.
2092 : : */
2093 : :
2094 : : Split *
2095 : 229 : xaccSplitGetOtherSplit (const Split *split)
2096 : : {
2097 : : Transaction *trans;
2098 : 229 : Split *other = nullptr;
2099 : :
2100 : 229 : if (!split) return nullptr;
2101 : 228 : trans = split->parent;
2102 : 228 : if (!trans) return nullptr;
2103 : :
2104 : 664 : for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
2105 : : {
2106 : 476 : Split *s = GNC_SPLIT(n->data);
2107 : 954 : if ((s == split) ||
2108 : 264 : (!xaccTransStillHasSplit(trans, s)) ||
2109 : 1003 : (xaccAccountGetType (xaccSplitGetAccount (s)) == ACCT_TYPE_TRADING) ||
2110 : 263 : (qof_instance_has_slot (QOF_INSTANCE (s), "lot-split")))
2111 : 214 : continue;
2112 : :
2113 : 262 : if (other)
2114 : 39 : return nullptr;
2115 : :
2116 : 223 : other = s;
2117 : : }
2118 : 188 : return other;
2119 : : }
2120 : :
2121 : : /********************************************************************\
2122 : : \********************************************************************/
2123 : :
2124 : : gnc_numeric
2125 : 66 : xaccSplitVoidFormerAmount(const Split *split)
2126 : : {
2127 : 66 : GValue v = G_VALUE_INIT;
2128 : 66 : gnc_numeric *num = nullptr;
2129 : : gnc_numeric retval;
2130 : 66 : g_return_val_if_fail(split, gnc_numeric_zero());
2131 : 66 : qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
2132 : 66 : if (G_VALUE_HOLDS_BOXED (&v))
2133 : 63 : num = (gnc_numeric*)g_value_get_boxed (&v);
2134 : 66 : retval = num ? *num : gnc_numeric_zero();
2135 : 66 : g_value_unset (&v);
2136 : 66 : return retval;
2137 : : }
2138 : :
2139 : : gnc_numeric
2140 : 12 : xaccSplitVoidFormerValue(const Split *split)
2141 : : {
2142 : 12 : GValue v = G_VALUE_INIT;
2143 : 12 : gnc_numeric *num = nullptr;
2144 : : gnc_numeric retval;
2145 : 12 : g_return_val_if_fail(split, gnc_numeric_zero());
2146 : 12 : qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
2147 : 12 : if (G_VALUE_HOLDS_BOXED (&v))
2148 : 9 : num = (gnc_numeric*)g_value_get_boxed (&v);
2149 : 12 : retval = num ? *num : gnc_numeric_zero();
2150 : 12 : g_value_unset (&v);
2151 : 12 : return retval;
2152 : : }
2153 : :
2154 : : void
2155 : 205 : xaccSplitVoid(Split *split)
2156 : : {
2157 : 205 : gnc_numeric zero = gnc_numeric_zero(), num;
2158 : 205 : GValue v = G_VALUE_INIT;
2159 : :
2160 : 205 : g_value_init (&v, GNC_TYPE_NUMERIC);
2161 : 205 : num = xaccSplitGetAmount(split);
2162 : 205 : g_value_set_boxed (&v, &num);
2163 : 205 : qof_instance_set_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
2164 : 205 : g_value_reset (&v);
2165 : 205 : num = xaccSplitGetValue(split);
2166 : 205 : g_value_set_boxed (&v, &num);
2167 : 205 : qof_instance_set_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
2168 : :
2169 : : /* Marking dirty handled by SetAmount etc. */
2170 : 205 : xaccSplitSetAmount (split, zero);
2171 : 205 : xaccSplitSetValue (split, zero);
2172 : 205 : xaccSplitSetReconcile(split, VREC);
2173 : 205 : g_value_unset (&v);
2174 : 205 : }
2175 : :
2176 : : void
2177 : 7 : xaccSplitUnvoid(Split *split)
2178 : : {
2179 : 7 : xaccSplitSetAmount (split, xaccSplitVoidFormerAmount(split));
2180 : 7 : xaccSplitSetValue (split, xaccSplitVoidFormerValue(split));
2181 : 7 : xaccSplitSetReconcile(split, NREC);
2182 : 7 : qof_instance_set_kvp (QOF_INSTANCE (split), nullptr, 1, void_former_amt_str);
2183 : 7 : qof_instance_set_kvp (QOF_INSTANCE (split), nullptr, 1, void_former_val_str);
2184 : 7 : qof_instance_set_dirty (QOF_INSTANCE (split));
2185 : 7 : }
2186 : :
2187 : : /********************************************************************\
2188 : : \********************************************************************/
2189 : : /* QofObject function implementation */
2190 : :
2191 : : /* Hook into the QofObject registry */
2192 : :
2193 : : #ifdef _MSC_VER
2194 : : /* MSVC compiler doesn't have C99 "designated initializers"
2195 : : * so we wrap them in a macro that is empty on MSVC. */
2196 : : # define DI(x) /* */
2197 : : #else
2198 : : # define DI(x) x
2199 : : #endif
2200 : : static QofObject split_object_def =
2201 : : {
2202 : : DI(.interface_version = ) QOF_OBJECT_VERSION,
2203 : : DI(.e_type = ) GNC_ID_SPLIT,
2204 : : DI(.type_label = ) "Split",
2205 : : DI(.create = ) (void* (*)(QofBook*))xaccMallocSplit,
2206 : : DI(.book_begin = ) nullptr,
2207 : : DI(.book_end = ) nullptr,
2208 : : DI(.is_dirty = ) qof_collection_is_dirty,
2209 : : DI(.mark_clean = ) qof_collection_mark_clean,
2210 : : DI(.foreach = ) qof_collection_foreach,
2211 : : DI(.printable = ) (const char * (*)(gpointer)) xaccSplitGetMemo,
2212 : : DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
2213 : : };
2214 : :
2215 : : static gpointer
2216 : 613 : split_account_guid_getter (gpointer obj, const QofParam *p)
2217 : : {
2218 : 613 : Split *s = GNC_SPLIT(obj);
2219 : : Account *acc;
2220 : :
2221 : 613 : if (!s) return nullptr;
2222 : 613 : acc = xaccSplitGetAccount (s);
2223 : 613 : if (!acc) return nullptr;
2224 : 613 : return ((gpointer)xaccAccountGetGUID (acc));
2225 : : }
2226 : :
2227 : : static double /* internal use only */
2228 : 0 : DxaccSplitGetShareAmount (const Split * split)
2229 : : {
2230 : 0 : return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
2231 : : }
2232 : :
2233 : : static gpointer
2234 : 3110 : no_op (gpointer obj, const QofParam *p)
2235 : : {
2236 : 3110 : return obj;
2237 : : }
2238 : :
2239 : : static void
2240 : 0 : qofSplitSetParentTrans(Split *s, QofInstance *ent)
2241 : : {
2242 : 0 : Transaction *trans = (Transaction*)ent;
2243 : :
2244 : 0 : g_return_if_fail(trans);
2245 : 0 : xaccSplitSetParent(s, trans);
2246 : : }
2247 : :
2248 : : static void
2249 : 0 : qofSplitSetAccount(Split *s, QofInstance *ent)
2250 : : {
2251 : 0 : Account *acc = (Account*)ent;
2252 : :
2253 : 0 : g_return_if_fail(acc);
2254 : 0 : xaccSplitSetAccount(s, acc);
2255 : : }
2256 : :
2257 : 81 : gboolean xaccSplitRegister (void)
2258 : : {
2259 : : static const QofParam params[] =
2260 : : {
2261 : : {
2262 : : SPLIT_DATE_RECONCILED, QOF_TYPE_DATE,
2263 : : (QofAccessFunc)xaccSplitGetDateReconciled,
2264 : : (QofSetterFunc)xaccSplitSetDateReconciledSecs
2265 : : },
2266 : :
2267 : : /* d-* are deprecated query params, should not be used in new
2268 : : * queries, should be removed from old queries. */
2269 : : {
2270 : : "d-share-amount", QOF_TYPE_DOUBLE,
2271 : : (QofAccessFunc)DxaccSplitGetShareAmount, nullptr
2272 : : },
2273 : : {
2274 : : "d-share-int64", QOF_TYPE_INT64,
2275 : : (QofAccessFunc)qof_entity_get_guid, nullptr
2276 : : },
2277 : : {
2278 : : SPLIT_BALANCE, QOF_TYPE_NUMERIC,
2279 : : (QofAccessFunc)xaccSplitGetBalance, nullptr
2280 : : },
2281 : : {
2282 : : SPLIT_CLEARED_BALANCE, QOF_TYPE_NUMERIC,
2283 : : (QofAccessFunc)xaccSplitGetClearedBalance, nullptr
2284 : : },
2285 : : {
2286 : : SPLIT_RECONCILED_BALANCE, QOF_TYPE_NUMERIC,
2287 : : (QofAccessFunc)xaccSplitGetReconciledBalance, nullptr
2288 : : },
2289 : : {
2290 : : SPLIT_MEMO, QOF_TYPE_STRING,
2291 : : (QofAccessFunc)xaccSplitGetMemo, (QofSetterFunc)qofSplitSetMemo
2292 : : },
2293 : : {
2294 : : SPLIT_ACTION, QOF_TYPE_STRING,
2295 : : (QofAccessFunc)xaccSplitGetAction, (QofSetterFunc)qofSplitSetAction
2296 : : },
2297 : : {
2298 : : SPLIT_RECONCILE, QOF_TYPE_CHAR,
2299 : : (QofAccessFunc)xaccSplitGetReconcile,
2300 : : (QofSetterFunc)qofSplitSetReconcile
2301 : : },
2302 : : {
2303 : : SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
2304 : : (QofAccessFunc)xaccSplitGetAmount, (QofSetterFunc)qofSplitSetAmount
2305 : : },
2306 : : {
2307 : : SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
2308 : : (QofAccessFunc)xaccSplitGetSharePrice,
2309 : : (QofSetterFunc)qofSplitSetSharePrice
2310 : : },
2311 : : {
2312 : : SPLIT_VALUE, QOF_TYPE_DEBCRED,
2313 : : (QofAccessFunc)xaccSplitGetValue, (QofSetterFunc)qofSplitSetValue
2314 : : },
2315 : : { SPLIT_TYPE, QOF_TYPE_STRING, (QofAccessFunc)xaccSplitGetType, nullptr },
2316 : : {
2317 : : SPLIT_VOIDED_AMOUNT, QOF_TYPE_NUMERIC,
2318 : : (QofAccessFunc)xaccSplitVoidFormerAmount, nullptr
2319 : : },
2320 : : {
2321 : : SPLIT_VOIDED_VALUE, QOF_TYPE_NUMERIC,
2322 : : (QofAccessFunc)xaccSplitVoidFormerValue, nullptr
2323 : : },
2324 : : { SPLIT_LOT, GNC_ID_LOT, (QofAccessFunc)xaccSplitGetLot, nullptr },
2325 : : {
2326 : : SPLIT_TRANS, GNC_ID_TRANS,
2327 : : (QofAccessFunc)xaccSplitGetParent,
2328 : : (QofSetterFunc)qofSplitSetParentTrans
2329 : : },
2330 : : {
2331 : : SPLIT_ACCOUNT, GNC_ID_ACCOUNT,
2332 : : (QofAccessFunc)xaccSplitGetAccount, (QofSetterFunc)qofSplitSetAccount
2333 : : },
2334 : : { SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, nullptr },
2335 : : /* these are no-ops to register the parameter names (for sorting) but
2336 : : they return an allocated object which getters cannot do. */
2337 : : { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, nullptr },
2338 : : { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, nullptr },
2339 : : { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, nullptr },
2340 : : { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, nullptr },
2341 : : {
2342 : : QOF_PARAM_GUID, QOF_TYPE_GUID,
2343 : : (QofAccessFunc)qof_entity_get_guid, nullptr
2344 : : },
2345 : : { nullptr },
2346 : : };
2347 : :
2348 : 81 : qof_class_register (GNC_ID_SPLIT, (QofSortFunc)xaccSplitOrder, params);
2349 : 81 : qof_class_register (SPLIT_ACCT_FULLNAME,
2350 : : (QofSortFunc)xaccSplitCompareAccountFullNames, nullptr);
2351 : 81 : qof_class_register (SPLIT_CORR_ACCT_NAME,
2352 : : (QofSortFunc)xaccSplitCompareOtherAccountFullNames,
2353 : : nullptr);
2354 : 81 : qof_class_register (SPLIT_CORR_ACCT_CODE,
2355 : : (QofSortFunc)xaccSplitCompareOtherAccountCodes, nullptr);
2356 : :
2357 : 81 : return qof_object_register (&split_object_def);
2358 : : }
2359 : :
2360 : : SplitTestFunctions*
2361 : 31 : _utest_split_fill_functions (void)
2362 : : {
2363 : 31 : SplitTestFunctions *func = g_new (SplitTestFunctions, 1);
2364 : :
2365 : 31 : func->xaccSplitEqualCheckBal = xaccSplitEqualCheckBal;
2366 : 31 : func->get_currency_denom = get_currency_denom;
2367 : 31 : func->get_commodity_denom = get_commodity_denom;
2368 : 31 : func->get_corr_account_split = get_corr_account_split;
2369 : 31 : return func;
2370 : : }
2371 : :
2372 : : /************************ END OF ************************************\
2373 : : \************************* FILE *************************************/
|