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