GnuCash  5.6-150-g038405b370+
split-register-model-save.c
1 /********************************************************************\
2  * split-register-model-save.c -- split register model object *
3  * Copyright (C) 2017 Aaron Laws *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact: *
17  * *
18  * Free Software Foundation Voice: +1-617-542-5942 *
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20  * Boston, MA 02110-1301, USA gnu@gnu.org *
21  * *
22 \********************************************************************/
23 
24 #include <config.h>
25 
26 #include <glib.h>
27 
28 #include "Scrub.h"
29 #include "SchedXaction.h"
30 #include "datecell.h"
31 #include "gnc-engine.h"
32 #include "engine-helpers.h"
33 #include "numcell.h"
34 #include "pricecell.h"
35 #include "recncell.h"
37 #include "split-register-p.h"
38 #include "gnc-exp-parser.h"
39 
40 
42 {
43  Transaction *trans;
44  Split *split;
45 
46  gboolean handled_dc; /* We have already handled the debit/credit cells. */
47  gboolean do_scrub; /* Scrub other split at the end. */
48  gboolean reg_expanded; /* Register is in expanded (split) mode */
49 };
50 
51 /* This static indicates the debugging module that this .o belongs to. */
52 static QofLogModule log_module = GNC_MOD_LEDGER;
53 
54 
55 static void
56 gnc_split_register_save_date_cell (BasicCell * cell,
57  gpointer save_data,
58  gpointer user_data)
59 {
60  SRSaveData *sd = save_data;
61  const char *value;
62  time64 cell_time;
63 
64  g_return_if_fail (gnc_basic_cell_has_name (cell, DATE_CELL));
65 
66  value = gnc_basic_cell_get_value (cell);
67 
68  DEBUG ("DATE: %s", value ? value : "(null)");
69 
70  gnc_date_cell_get_date ((DateCell *) cell, &cell_time, TRUE);
71 
72  /* commit any pending changes */
73  gnc_date_cell_commit ((DateCell *) cell);
74 
75  xaccTransSetDatePostedSecsNormalized (sd->trans, cell_time);
76 }
77 
78 static void
79 gnc_split_register_save_type_cell (BasicCell * cell,
80  gpointer save_data,
81  gpointer user_data)
82 {
83  SRSaveData *sd = save_data;
84  char value;
85 
86  g_return_if_fail (gnc_basic_cell_has_name (cell, TYPE_CELL));
87 
88  value = gnc_recn_cell_get_flag ((RecnCell *)cell);
89 
90  xaccTransSetTxnType (sd->trans, value);
91 }
92 
93 static void
94 gnc_split_register_save_due_date_cell (BasicCell * cell,
95  gpointer save_data,
96  gpointer user_data)
97 {
98  SRSaveData *sd = save_data;
99  const char *value;
100  time64 time;
101  g_return_if_fail (gnc_basic_cell_has_name (cell, DDUE_CELL));
102  value = gnc_basic_cell_get_value (cell);
103  /* commit any pending changes */
104  gnc_date_cell_commit ((DateCell *) cell);
105  DEBUG ("DATE: %s", value ? value : "(null)");
106  gnc_date_cell_get_date ((DateCell *) cell, &time, TRUE);
107  xaccTransSetDateDue (sd->trans, time);
108 }
109 
110 static void
111 gnc_split_register_save_num_cell (BasicCell * cell,
112  gpointer save_data,
113  gpointer user_data)
114 {
115  SRSaveData *sd = save_data;
116  SplitRegister *reg = user_data;
117  const char *value;
118 
119  g_return_if_fail (gnc_basic_cell_has_name (cell, NUM_CELL));
120 
121  value = gnc_basic_cell_get_value (cell);
122 
123  DEBUG ("NUM: %s\n", value ? value : "(null)");
124 
125  /* set per book option */
126  gnc_set_num_action (sd->trans, sd->split, value, NULL);
127 
128  if (gnc_num_cell_set_last_num ((NumCell *) cell, value))
129  {
130  SRInfo *info = gnc_split_register_get_info (reg);
131  Split *blank_split = xaccSplitLookup (&info->blank_split_guid,
132  gnc_get_current_book ());
133  Transaction *blank_trans = xaccSplitGetParent (blank_split);
134 
135  if (sd->trans == blank_trans)
136  gnc_split_register_set_last_num (reg, gnc_basic_cell_get_value (cell));
137  }
138 }
139 
140 static void
141 gnc_split_register_save_tnum_cell (BasicCell * cell,
142  gpointer save_data,
143  gpointer user_data)
144 {
145  SRSaveData *sd = save_data;
146  const char *value;
147 
148  g_return_if_fail (gnc_basic_cell_has_name (cell, TNUM_CELL));
149 
150  value = gnc_basic_cell_get_value (cell);
151 
152  DEBUG ("TNUM: %s\n", value ? value : "(null)");
153 
154  /* set tran-num using utility function */
155  gnc_set_num_action (sd->trans, NULL, value, NULL);
156 }
157 
158 static void
159 gnc_split_register_save_desc_cell (BasicCell * cell,
160  gpointer save_data,
161  gpointer user_data)
162 {
163  SRSaveData *sd = save_data;
164  const char *value;
165 
166  g_return_if_fail (gnc_basic_cell_has_name (cell, DESC_CELL));
167 
168  value = gnc_basic_cell_get_value (cell);
169 
170  DEBUG ("DESC: %s", value ? value : "(null)");
171 
172  xaccTransSetDescription (sd->trans, value);
173 }
174 
175 static void
176 gnc_split_register_save_notes_cell (BasicCell * cell,
177  gpointer save_data,
178  gpointer user_data)
179 {
180  SRSaveData *sd = save_data;
181  const char *value;
182 
183  g_return_if_fail (gnc_basic_cell_has_name (cell, NOTES_CELL));
184 
185  value = gnc_basic_cell_get_value (cell);
186 
187  DEBUG ("NOTES: %s", value ? value : "(null)");
188 
189  xaccTransSetNotes (sd->trans, value);
190 }
191 
192 static void
193 gnc_split_register_save_recn_cell (BasicCell * bcell,
194  gpointer save_data,
195  gpointer user_data)
196 {
197  SRSaveData *sd = save_data;
198  RecnCell *cell = (RecnCell *) bcell;
199 
200  g_return_if_fail (gnc_basic_cell_has_name (bcell, RECN_CELL));
201 
202  DEBUG ("RECN: %c", gnc_recn_cell_get_flag (cell));
203 
204  xaccSplitSetReconcile (sd->split, gnc_recn_cell_get_flag (cell));
205 }
206 
207 static void
208 gnc_split_register_save_actn_cell (BasicCell * cell,
209  gpointer save_data,
210  gpointer user_data)
211 {
212  SRSaveData *sd = save_data;
213  const char *value;
214 
215  g_return_if_fail (gnc_basic_cell_has_name (cell, ACTN_CELL));
216 
217  value = gnc_basic_cell_get_value (cell);
218 
219  DEBUG ("ACTN: %s", value ? value : "(null)");
220 
221  /* Set split-action with gnc_set_num_action which is the same as
222  * xaccSplitSetAction with these arguments */
223  gnc_set_num_action (NULL, sd->split, NULL, value);
224 }
225 
226 static void
227 gnc_split_register_save_memo_cell (BasicCell * cell,
228  gpointer save_data,
229  gpointer user_data)
230 {
231  SRSaveData *sd = save_data;
232  const char *value;
233 
234  g_return_if_fail (gnc_basic_cell_has_name (cell, MEMO_CELL));
235 
236  value = gnc_basic_cell_get_value (cell);
237 
238  DEBUG ("MEMO: %s", value ? value : "(null)");
239 
240  xaccSplitSetMemo (sd->split, value);
241 }
242 
243 /* OK, the handling of transfers gets complicated because it depends
244  * on what was displayed to the user. For a multi-line display, we
245  * just reparent the indicated split. For a two-line display, we want
246  * to reparent the "other" split, but only if there is one. XFRM is
247  * the straight split, MXFRM is the mirrored split. */
248 static void
249 gnc_split_register_save_xfrm_cell (BasicCell * cell,
250  gpointer save_data,
251  gpointer user_data)
252 {
253  SRSaveData *sd = save_data;
254  SplitRegister *reg = user_data;
255  Account *old_acc;
256  Account *new_acc;
257 
258  g_return_if_fail (gnc_basic_cell_has_name (cell, XFRM_CELL));
259 
260  old_acc = xaccSplitGetAccount (sd->split);
261 
262  new_acc = gnc_split_register_get_account (reg, XFRM_CELL);
263 
264  if ((new_acc != NULL) && (old_acc != new_acc))
265  xaccAccountInsertSplit (new_acc, sd->split);
266 }
267 
268 static void
269 gnc_split_register_save_mxfrm_cell (BasicCell * cell,
270  gpointer save_data,
271  gpointer user_data)
272 {
273  SRSaveData *sd = save_data;
274  SplitRegister *reg = user_data;
275  Split * other_split;
276 
277  g_return_if_fail (gnc_basic_cell_has_name (cell, MXFRM_CELL));
278 
279  other_split = xaccSplitGetOtherSplit (sd->split);
280 
281  /* other_split may be null for two very different reasons:
282  * (1) the parent transaction has three or more splits in it,
283  * and so the "other" split is ambiguous, and thus null.
284  * (2) the parent transaction has only this one split as a child.
285  * and "other" is null because there is no other.
286  *
287  * In the case (2), we want to create the other split, so that
288  * the user's request to transfer actually works out. */
289 
290  if (!other_split)
291  {
292  other_split = xaccTransGetSplit (sd->trans, 1);
293 
294  if (!other_split)
295  {
296  other_split = xaccMallocSplit (gnc_get_current_book ());
297  xaccTransAppendSplit (sd->trans, other_split);
298  }
299  }
300 
301  if (other_split)
302  {
303  Account *old_acc;
304  Account *new_acc;
305 
306  /* Do some reparenting. Insertion into new account
307  * will automatically delete from the old account. */
308  old_acc = xaccSplitGetAccount (other_split);
309  new_acc = gnc_split_register_get_account (reg, MXFRM_CELL);
310 
311  if ((new_acc != NULL) && (old_acc != new_acc))
312  xaccAccountInsertSplit (new_acc, other_split);
313  }
314 }
315 
316 static void
317 gnc_split_register_save_shares_cell (BasicCell * bcell,
318  gpointer save_data,
319  gpointer user_data)
320 {
321  SRSaveData *sd = save_data;
322  PriceCell *cell = (PriceCell *) bcell;
323  gnc_numeric amount;
324 
325  g_return_if_fail (gnc_basic_cell_has_name (bcell, SHRS_CELL));
326 
327  amount = gnc_price_cell_get_value (cell);
328 
329  DEBUG ("SHRS");
330 
331  xaccSplitSetAmount (sd->split, amount);
332 
333  sd->do_scrub = TRUE;
334 }
335 
336 static void
337 gnc_split_register_save_price_cell (BasicCell * bcell,
338  gpointer save_data,
339  gpointer user_data)
340 {
341  SRSaveData *sd = save_data;
342  PriceCell *cell = (PriceCell *) bcell;
343  gnc_numeric price;
344 
345  g_return_if_fail (gnc_basic_cell_has_name (bcell, PRIC_CELL));
346 
347  price = gnc_price_cell_get_value (cell);
348 
349  DEBUG ("PRIC");
350 
351  /* If we handled the Debcred cell then don't set the share price! */
352  if (!sd->handled_dc)
353  xaccSplitSetSharePrice (sd->split, price);
354 
355  sd->do_scrub = TRUE;
356 }
357 
358 gnc_numeric
359 gnc_split_register_debcred_cell_value (SplitRegister *reg)
360 {
361  PriceCell *cell;
362  gnc_numeric new_amount;
363  gnc_numeric credit;
364  gnc_numeric debit;
365 
366  cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
367  CRED_CELL);
368  credit = gnc_price_cell_get_value (cell);
369 
370  cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
371  DEBT_CELL);
372  debit = gnc_price_cell_get_value (cell);
373 
374  new_amount = gnc_numeric_sub_fixed (debit, credit);
375 
376  return new_amount;
377 }
378 
379 static gnc_numeric
380 gnc_split_register_get_rate_cell (SplitRegister *reg, const char *cell_name)
381 {
382  PriceCell *rate_cell;
383 
384  rate_cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout,
385  cell_name);
386  if (rate_cell)
387  return gnc_price_cell_get_value (rate_cell);
388 
389  /* Uhh, just return '1' */
390  return gnc_numeric_create (100, 100);
391 }
392 
393 gboolean
394 gnc_split_register_split_needs_amount (SplitRegister *reg, Split *split)
395 {
396  Transaction *txn = xaccSplitGetParent (split);
397  Account *acc = xaccSplitGetAccount (split);
398 
399  return gnc_split_register_needs_conv_rate (reg, txn, acc);
400 }
401 
402 static void
403 gnc_split_register_save_amount_values (SRSaveData *sd, SplitRegister *reg)
404 {
405  Account *acc;
406  gnc_numeric new_amount, convrate, amtconv, value;
407  gnc_commodity *curr, *reg_com, *xfer_com;
408  Account *xfer_acc;
409 
410  new_amount = gnc_split_register_debcred_cell_value (reg);
411  acc = gnc_split_register_get_default_account (reg);
412 
413  xfer_acc = xaccSplitGetAccount (sd->split);
414  xfer_com = xaccAccountGetCommodity (xfer_acc);
415  reg_com = xaccAccountGetCommodity (acc);
416  curr = xaccTransGetCurrency (sd->trans);
417 
418  /* First, compute the conversion rate to convert the value to the
419  * amount.
420  */
421  amtconv = convrate = gnc_split_register_get_rate_cell (reg, RATE_CELL);
422  if (acc && gnc_split_register_needs_conv_rate (reg, sd->trans, acc))
423  {
424 
425  /* If we are in an expanded register and the xfer_acc->comm !=
426  * reg_acc->comm then we need to compute the convrate here.
427  * Otherwise, we _can_ use the rate_cell!
428  */
429  if (sd->reg_expanded && ! gnc_commodity_equal (reg_com, xfer_com))
430  amtconv = xaccTransGetAccountConvRate(sd->trans, acc);
431  }
432 
433  if (xaccTransUseTradingAccounts (sd->trans))
434  {
435  /* Using currency accounts, the amount is probably really the
436  amount and not the value. */
437  gboolean is_amount;
438  if (reg->type == STOCK_REGISTER ||
439  reg->type == CURRENCY_REGISTER ||
440  reg->type == PORTFOLIO_LEDGER)
441  {
442  if (xaccAccountIsPriced(xfer_acc) ||
444  is_amount = FALSE;
445  else
446  is_amount = TRUE;
447  }
448  else
449  {
450  is_amount = TRUE;
451  }
452 
453  if (is_amount)
454  {
455  xaccSplitSetAmount(sd->split, new_amount);
456  if (gnc_split_register_split_needs_amount (reg, sd->split))
457  {
458  value = gnc_numeric_div(new_amount, amtconv,
461  xaccSplitSetValue(sd->split, value);
462  }
463  else
464  xaccSplitSetValue(sd->split, new_amount);
465  }
466  else
467  {
468  xaccSplitSetValue(sd->split, new_amount);
469  }
470 
471  return;
472  }
473 
474  /* How to interpret new_amount depends on our view of this
475  * transaction. If we're sitting in an account with the same
476  * commodity as the transaction, then we can set the Value and then
477  * compute the amount. Otherwise we are setting the "converted
478  * value". This means we need to convert new_amount to the actual
479  * 'value' by dividing by the convrate in order to set the value.
480  */
481 
482  /* Now compute/set the split value. Amount is in the register
483  * currency but we need to convert to the txn currency.
484  */
485  if (acc && gnc_split_register_needs_conv_rate (reg, sd->trans, acc))
486  {
487 
488  /* convert the amount to the Value ... */
489  value = gnc_numeric_div (new_amount, amtconv,
492  xaccSplitSetValue (sd->split, value);
493  }
494  else
495  xaccSplitSetValue (sd->split, new_amount);
496 
497  /* Now re-compute the Amount from the Value. We may need to convert
498  * from the Value back to the amount here using the convrate from
499  * earlier.
500  */
501  value = xaccSplitGetValue (sd->split);
502 
503  if (gnc_split_register_split_needs_amount (reg, sd->split))
504  {
505  acc = xaccSplitGetAccount (sd->split);
506  new_amount = gnc_numeric_mul (value, convrate,
509  xaccSplitSetAmount (sd->split, new_amount);
510  }
511 }
512 
513 static void
514 gnc_split_register_save_debcred_cell (BasicCell * bcell,
515  gpointer save_data,
516  gpointer user_data)
517 {
518  SRSaveData *sd = save_data;
519  SplitRegister *reg = user_data;
520 
521  g_return_if_fail (gnc_basic_cell_has_name (bcell, DEBT_CELL) ||
522  gnc_basic_cell_has_name (bcell, CRED_CELL));
523 
524  if (sd->handled_dc)
525  return;
526 
527  gnc_split_register_save_amount_values (sd, reg);
528 
529  sd->handled_dc = TRUE;
530  sd->do_scrub = TRUE;
531 }
532 
533 static void
534 gnc_split_register_save_rate_cell (BasicCell * bcell,
535  gpointer save_data,
536  gpointer user_data)
537 {
538  SRSaveData *sd = save_data;
539 
540  /* if the exchrate cell changed, then make sure to force a scrub */
541  sd->do_scrub = TRUE;
542 }
543 
544 static void
545 gnc_split_register_save_cells (gpointer save_data,
546  gpointer user_data)
547 {
548  SRSaveData *sd = save_data;
549  SplitRegister *reg = user_data;
550  Split *other_split;
551  gnc_commodity *txn_cur;
552  gnc_numeric rate;
553 
554  g_return_if_fail (sd != NULL);
555 
556  if (!sd->do_scrub)
557  return;
558 
559  other_split = xaccSplitGetOtherSplit (sd->split);
560  txn_cur = xaccTransGetCurrency (sd->trans);
561 
562  xaccSplitScrub (sd->split);
563 
564  rate = gnc_split_register_get_rate_cell (reg, RATE_CELL);
565 
566  if (other_split && !sd->reg_expanded)
567  {
568  gnc_numeric amount, value = xaccSplitGetValue (sd->split);
569  Account *acc;
570  gboolean split_needs_amount;
571 
572  split_needs_amount = gnc_split_register_split_needs_amount(reg, sd->split);
573 
574  /* We are changing the rate on the current split, but it was not
575  * handled in the debcred handler, so we need to do it here.
576  */
577  if (!sd->handled_dc && split_needs_amount && !gnc_numeric_zero_p (rate))
578  {
579  gnc_numeric amount = xaccSplitGetAmount (sd->split);
580  value = gnc_numeric_div(
581  amount, rate, gnc_commodity_get_fraction(txn_cur), GNC_HOW_RND_ROUND_HALF_UP);
582  xaccSplitSetValue (sd->split, value);
583 
584  /* XXX: do we need to set the amount on the other split? */
585  }
586 
587  /* Now reverse the value for the other split */
588  value = gnc_numeric_neg (value);
589 
590  if (gnc_split_register_split_needs_amount (reg, other_split))
591  {
592  acc = xaccSplitGetAccount (other_split);
593 
594  /* If we don't have an exchange rate then figure it out. Or, if
595  * BOTH splits require an amount, then most likely we're in the
596  * strange case of having a transaction currency different than
597  * _both_ accounts -- so grab the other exchange rate.
598  */
599  if (gnc_numeric_zero_p (rate) || split_needs_amount)
600  rate = xaccTransGetAccountConvRate(xaccSplitGetParent (other_split),
601  acc);
602 
603  amount = gnc_numeric_mul (value, rate, xaccAccountGetCommoditySCU (acc),
605  xaccSplitSetAmount (other_split, amount);
606 
607  }
608 
609  xaccSplitSetValue (other_split, value);
610 
611  xaccSplitScrub (other_split);
612  }
613  else if (gnc_split_register_split_needs_amount (reg, sd->split) &&
614  ! gnc_numeric_zero_p (rate))
615  {
616  /* this is either a multi-split or expanded transaction, so only
617  * deal with this split... In particular we need to reset the
618  * Value if the conv-rate changed.
619  *
620  * If we handled the debcred then no need to do anything there --
621  * the debcred handler did all the computation. If NOT, then the
622  * convrate changed -- reset the value from the amount.
623  */
624  if (!sd->handled_dc)
625  {
626  gnc_split_register_save_amount_values (sd, reg);
627 #if 0
628  gnc_numeric value, amount;
629 
630  amount = xaccSplitGetAmount (sd->split);
631  value = gnc_numeric_div (amount, rate, gnc_commodity_get_fraction (txn_cur),
633  xaccSplitSetValue (sd->split, value);
634 #endif
635  }
636  }
637 }
638 
639 static void
640 gnc_template_register_save_unexpected_cell (BasicCell * cell,
641  gpointer save_data,
642  gpointer user_data)
643 {
644  PERR ("unexpected changed fields in a template register");
645 }
646 
647 static void
648 gnc_template_register_save_xfrm_cell (BasicCell * cell,
649  gpointer save_data,
650  gpointer user_data)
651 {
652  SRSaveData *sd = save_data;
653  SplitRegister *reg = user_data;
654  SRInfo *info = gnc_split_register_get_info (reg);
655  Account *template_acc;
656  const GncGUID *acctGUID;
657  Account *acct;
658 
659  g_return_if_fail (gnc_basic_cell_has_name (cell, XFRM_CELL));
660 
661  /* save the account GncGUID into the kvp_data. */
662  acct = gnc_split_register_get_account (reg, XFRM_CELL);
663  if (!acct)
664  {
665  PERR ("unknown account");
666  return;
667  }
668 
669  acctGUID = xaccAccountGetGUID (acct);
670  qof_instance_set (QOF_INSTANCE (sd->split),
671  "sx-account", acctGUID,
672  NULL);
673  template_acc = xaccAccountLookup (&info->template_account,
674  gnc_get_current_book ());
675 
676  /* set the actual account to the fake account for these templates */
677  xaccAccountInsertSplit (template_acc, sd->split);
678 }
679 
680 static void
681 gnc_template_register_save_mxfrm_cell (BasicCell * cell,
682  gpointer save_data,
683  gpointer user_data)
684 {
685 }
686 
687 static void
688 save_cell (SplitRegister *reg, Split* split, const char *cell_name)
689 {
690  const gboolean is_credit = g_strcmp0 (cell_name, FCRED_CELL) == 0;
691  const char *formula = is_credit ?
692  "sx-credit-formula" : "sx-debit-formula";
693  const char *numeric = is_credit ?
694  "sx-credit-numeric" : "sx-debit-numeric";
695  const char *value = gnc_table_layout_get_cell_value (reg->table->layout,
696  cell_name);
697  gnc_numeric new_amount = gnc_numeric_zero ();
698  GHashTable *parser_vars = g_hash_table_new (g_str_hash, g_str_equal);
699  char *error_loc;
700 
701  /* If the value can be parsed into a numeric result (without any
702  * further variable definitions), store that numeric value
703  * additionally in the kvp. Otherwise store a zero numeric
704  * there.*/
705  const gboolean parse_result =
706  gnc_exp_parser_parse_separate_vars (value, &new_amount,
707  &error_loc, parser_vars);
708  if (!parse_result || g_hash_table_size (parser_vars) != 0)
709  new_amount = gnc_numeric_zero ();
710  g_hash_table_unref (parser_vars);
711  qof_instance_set (QOF_INSTANCE (split),
712  numeric, &new_amount,
713  formula, value,
714  NULL);
715 }
716 
717 static void
718 gnc_template_register_save_debcred_cell (BasicCell * cell,
719  gpointer save_data,
720  gpointer user_data)
721 {
722  SRSaveData *sd = save_data;
723  SplitRegister *reg = user_data;
724 
725  g_return_if_fail (gnc_basic_cell_has_name (cell, FDEBT_CELL) ||
726  gnc_basic_cell_has_name (cell, FCRED_CELL));
727 
728  if (sd->handled_dc)
729  return;
730 
731  save_cell (reg, sd->split, FCRED_CELL);
732  save_cell (reg, sd->split, FDEBT_CELL);
733 
734  /* set the amount to an innocuous value */
735  /* Note that this marks the split dirty */
736  xaccSplitSetValue (sd->split, gnc_numeric_create (0, 1));
737 
738  sd->handled_dc = TRUE;
739 }
740 
741 static void
742 gnc_template_register_save_shares_cell (BasicCell * cell,
743  gpointer save_data,
744  gpointer user_data)
745 {
746  SRSaveData *sd = save_data;
747  char *sharesStr = "(x + y)/42";
748 
749  g_return_if_fail (gnc_basic_cell_has_name (cell, SHRS_CELL));
750  /* FIXME: shares cells are numeric by definition. */
751  qof_instance_set (QOF_INSTANCE (sd->split),
752  "sx-shares", sharesStr,
753  NULL);
754 
755  /* set the shares to an innocuous value */
756  /* Note that this marks the split dirty */
758  gnc_numeric_create (0, 1),
759  gnc_numeric_create (0, 1));
760 }
761 
762 void
763 gnc_split_register_model_add_save_handlers (TableModel *model)
764 {
765  g_return_if_fail (model != NULL);
766 
767  gnc_table_model_set_save_handler (model,
768  gnc_split_register_save_date_cell,
769  DATE_CELL);
770 
771  gnc_table_model_set_save_handler (model,
772  gnc_split_register_save_due_date_cell,
773  DDUE_CELL);
774 
775  gnc_table_model_set_save_handler (model,
776  gnc_split_register_save_type_cell,
777  TYPE_CELL);
778 
779  gnc_table_model_set_save_handler (model,
780  gnc_split_register_save_num_cell,
781  NUM_CELL);
782 
783  gnc_table_model_set_save_handler (model,
784  gnc_split_register_save_tnum_cell,
785  TNUM_CELL);
786 
787  gnc_table_model_set_save_handler (model,
788  gnc_split_register_save_desc_cell,
789  DESC_CELL);
790 
791  gnc_table_model_set_save_handler (model,
792  gnc_split_register_save_notes_cell,
793  NOTES_CELL);
794 
795  gnc_table_model_set_save_handler (model,
796  gnc_split_register_save_recn_cell,
797  RECN_CELL);
798 
799  gnc_table_model_set_save_handler (model,
800  gnc_split_register_save_actn_cell,
801  ACTN_CELL);
802 
803  gnc_table_model_set_save_handler (model,
804  gnc_split_register_save_memo_cell,
805  MEMO_CELL);
806 
807  gnc_table_model_set_save_handler (model,
808  gnc_split_register_save_xfrm_cell,
809  XFRM_CELL);
810 
811  gnc_table_model_set_save_handler (model,
812  gnc_split_register_save_mxfrm_cell,
813  MXFRM_CELL);
814 
815  gnc_table_model_set_save_handler (model,
816  gnc_split_register_save_shares_cell,
817  SHRS_CELL);
818 
819  gnc_table_model_set_save_handler (model,
820  gnc_split_register_save_price_cell,
821  PRIC_CELL);
822 
823  gnc_table_model_set_save_handler (model,
824  gnc_split_register_save_debcred_cell,
825  DEBT_CELL);
826 
827  gnc_table_model_set_save_handler (model,
828  gnc_split_register_save_debcred_cell,
829  CRED_CELL);
830 
831  gnc_table_model_set_save_handler (model,
832  gnc_split_register_save_rate_cell,
833  RATE_CELL);
834 
835  gnc_table_model_set_post_save_handler (model, gnc_split_register_save_cells);
836 }
837 
838 void
839 gnc_template_register_model_add_save_handlers (TableModel *model)
840 {
841  g_return_if_fail (model != NULL);
842 
843  gnc_split_register_model_add_save_handlers (model);
844 
845  gnc_table_model_set_save_handler (model,
846  gnc_template_register_save_unexpected_cell,
847  DATE_CELL);
848 
849  gnc_table_model_set_save_handler (model,
850  gnc_template_register_save_unexpected_cell,
851  DDUE_CELL);
852 
853  gnc_table_model_set_save_handler (model,
854  gnc_template_register_save_xfrm_cell,
855  XFRM_CELL);
856 
857  gnc_table_model_set_save_handler (model,
858  gnc_template_register_save_mxfrm_cell,
859  MXFRM_CELL);
860 
861  gnc_table_model_set_save_handler (model,
862  gnc_template_register_save_debcred_cell,
863  FDEBT_CELL);
864 
865  gnc_table_model_set_save_handler (model,
866  gnc_template_register_save_debcred_cell,
867  FCRED_CELL);
868 
869  gnc_table_model_set_save_handler (model,
870  gnc_template_register_save_shares_cell,
871  SHRS_CELL);
872 }
873 
874 SRSaveData *
875 gnc_split_register_save_data_new (Transaction *trans, Split *split,
876  gboolean expanded)
877 {
878  SRSaveData *sd;
879 
880  g_return_val_if_fail (trans != NULL, NULL);
881  g_return_val_if_fail (split != NULL, NULL);
882 
883  sd = g_new0 (SRSaveData, 1);
884 
885  sd->trans = trans;
886  sd->split = split;
887  sd->handled_dc = FALSE;
888  sd->do_scrub = FALSE;
889  sd->reg_expanded = expanded;
890 
891  return sd;
892 }
893 
894 void
895 gnc_split_register_save_data_destroy (SRSaveData *sd)
896 {
897  g_free (sd);
898 }
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
The RecnCell object implements a cell handler that will cycle through a series of single-character va...
Definition: recncell.h:47
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:381
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4490
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2696
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
STRUCTS.
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
Save handlers for the SplitRegister Model and Template SplitRegister model.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define xaccAccountGetGUID(X)
Definition: Account.h:248
void xaccTransSetTxnType(Transaction *trans, char type)
Set the Transaction Type: note the type will be saved into the Transaction kvp property as a backward...
convert single-entry accounts to clean double-entry
Definition: finvar.h:98
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1070
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
The PriceCell object implements a cell handler that stores a single double-precision value...
Definition: pricecell.h:54
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
void xaccSplitSetSharePriceAndAmount(Split *s, gnc_numeric price, gnc_numeric amt)
The xaccSplitSetSharePriceAndAmount() method will simultaneously update the share price and the numbe...
Definition: Split.cpp:1158
void gnc_date_cell_get_date(DateCell *cell, time64 *time, gboolean warn)
Set a time64 to the value in the DateCell.
void gnc_date_cell_commit(DateCell *cell)
Commits any pending changes to the value of the cell.
void xaccSplitScrub(Split *split)
The xaccSplitScrub method ensures that if this split has the same commodity and currency, then it will have the same amount and value.
Definition: Scrub.cpp:424
private declarations for SplitRegister
void xaccTransSetDateDue(Transaction *trans, time64 time)
Dates and txn-type for A/R and A/P "invoice" postings.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
All type declarations for the whole Gnucash engine.
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
The NumCell object implements a number handling cell.
Definition: numcell.h:39
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3359
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1048
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
void xaccSplitSetSharePrice(Split *s, gnc_numeric price)
Definition: Split.cpp:1186
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
The DateCell object implements a date handling cell.
Definition: datecell.h:91
Scheduled Transactions public handling routines.
The type used to store guids in C.
Definition: guid.h:75
gnc_numeric gnc_price_cell_get_value(PriceCell *cell)
return the value of a price cell
Definition: pricecell.c:208
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2032