1 /********************************************************************\
2  * gnc-tree-util-split-reg.c -- GtkTreeView implementation          *
3  *                     to display registers in a GtkTreeView.       *
4  *                                                                  *
5  * Copyright (C) 2006-2007 Chris Shoemaker <c.shoemaker@cox.net>    *
6  * Copyright (C) 2012 Robert Fewell                                 *
7  *                                                                  *
8  * This program is free software; you can redistribute it and/or    *
9  * modify it under the terms of the GNU General Public License as   *
10  * published by the Free Software Foundation; either version 2 of   *
11  * the License, or (at your option) any later version.              *
12  *                                                                  *
13  * This program is distributed in the hope that it will be useful,  *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
16  * GNU General Public License for more details.                     *
17  *                                                                  *
18  * You should have received a copy of the GNU General Public License*
19  * along with this program; if not, contact:                        *
20  *                                                                  *
21  * Free Software Foundation           Voice:  +1-617-542-5942       *
22  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
23  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
24  *                                                                  *
25 \********************************************************************/
26 
27 #include <config.h>
28 
29 #include <gtk/gtk.h>
30 #include <glib/gi18n.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "gnc-tree-util-split-reg.h"
35 #include "gnc-tree-model-split-reg.h"
36 #include "gnc-tree-view-split-reg.h"
37 
38 #include "gnc-ui.h"
39 #include "dialog-utils.h"
40 #include "dialog-transfer.h"
41 #include "engine-helpers.h"
42 #include "Transaction.h"
43 
44 
45 #define SPLIT_TRANS_STR _("-- Split Transaction --")
46 #define STOCK_SPLIT_STR _("-- Stock Split --")
47 
48 /** Static Globals *******************************************************/
49 static QofLogModule log_module = GNC_MOD_LEDGER;
50 
51 /*****************************************************************************/
52 
53 
54 /* Is current split a security account */
55 static gboolean
gtu_sr_use_security(GncTreeViewSplitReg * view)56 gtu_sr_use_security (GncTreeViewSplitReg *view)
57 {
58     RowDepth depth;
59     Account *account = NULL;
60     Split *split;
61 
62     split = gnc_tree_view_split_reg_get_current_split (view);
63 
64     depth = gnc_tree_view_reg_get_selected_row_depth (view);
65 
66     if (!split)
67         return TRUE;
68 
69     if (depth != SPLIT3)
70         return TRUE;
71 
72     if (!account)
73         account = xaccSplitGetAccount (split);
74 
75     if (!account)
76         return TRUE;
77 
78     if (xaccTransUseTradingAccounts (xaccSplitGetParent (split)))
79     {
80         if (!gnc_commodity_is_iso (xaccAccountGetCommodity (account)))
81             return TRUE;
82     }
83 
84     return xaccAccountIsPriced (account);
85 }
86 
87 
88 /* Get the rate from the price db */
89 static gnc_numeric
gtu_sr_get_rate_from_db(gnc_commodity * from,gnc_commodity * to)90 gtu_sr_get_rate_from_db (gnc_commodity *from, gnc_commodity *to)
91 {
92     GNCPrice *prc;
93     QofBook *book = gnc_get_current_book ();
94 
95     prc = gnc_pricedb_lookup_latest (gnc_pricedb_get_db (book), from, to);
96 
97     if (!prc)
98         return gnc_numeric_create (100, 100);
99 
100     if (gnc_commodity_equiv(from, gnc_price_get_currency(prc)))
101         return gnc_numeric_invert(gnc_price_get_value(prc));
102     return gnc_price_get_value(prc);
103 }
104 
105 
106 /* Do we need an exchange rate */
107 static gboolean
gtu_sr_needs_exchange_rate(GncTreeViewSplitReg * view,Transaction * trans,Split * split)108 gtu_sr_needs_exchange_rate (GncTreeViewSplitReg *view, Transaction *trans, Split *split)
109 {
110     gnc_commodity *split_com, *txn_curr, *reg_com;
111 
112     ENTER("gtu_sr_needs_exchange_rate - trans %p and split %p", trans, split);
113 
114     txn_curr = xaccTransGetCurrency (trans);
115     split_com = xaccAccountGetCommodity (xaccSplitGetAccount (split));
116     if (split_com && txn_curr && !gnc_commodity_equiv (split_com, txn_curr))
117     {
118         LEAVE("gtu_sr_needs_exchange_rate split_com to txn_curr return TRUE");
119         return TRUE;
120     }
121 
122     reg_com = gnc_tree_view_split_reg_get_reg_commodity (view);
123     if (split_com && reg_com && !gnc_commodity_equiv (split_com, reg_com))
124     {
125         LEAVE("gtu_sr_needs_exchange_rate split_com and reg_com return TRUE");
126         return TRUE;
127     }
128     LEAVE("No Exchange rate needed");
129     return FALSE;
130 }
131 
132 
133 /* Either sets the value and amount for split and returns TRUE, or
134    does nothing and returns FALSE. */
135 static gboolean
gtu_sr_handle_exchange_rate(GncTreeViewSplitReg * view,gnc_numeric amount,Transaction * trans,Split * split,gboolean force)136 gtu_sr_handle_exchange_rate (GncTreeViewSplitReg *view, gnc_numeric amount, Transaction *trans, Split *split, gboolean force)
137 {
138     GncTreeModelSplitReg *model;
139     XferDialog *xfer;
140     gboolean rate_split_ok, rate_reg_ok;
141     gnc_numeric rate_split, rate_reg, value;
142     Account *reg_acc;
143     gnc_commodity *xfer_comm = xaccAccountGetCommodity (xaccSplitGetAccount (split));
144     gnc_commodity *reg_comm = gnc_tree_view_split_reg_get_reg_commodity (view);
145     gnc_commodity *trans_curr = xaccTransGetCurrency (trans);
146     gboolean expanded;
147     gboolean have_rate = TRUE;
148 
149     ENTER("handle_exchange_rate amount %s, trans %p and split %p force %d", gnc_numeric_to_string (amount), trans, split, force);
150 
151 
152     model = gnc_tree_view_split_reg_get_model_from_view (view);
153 
154     reg_acc = gnc_tree_model_split_reg_get_anchor (model);
155 
156     /* Rate from trans-curr to split-comm */
157     rate_split_ok = xaccTransGetRateForCommodity (trans, xfer_comm, split, &rate_split);
158     DEBUG("rate_split_ok %d and xfer_comm %s", rate_split_ok, gnc_commodity_get_fullname (xfer_comm));
159 
160     /* Rate from trans-curr to reg-comm */
161     rate_reg_ok = xaccTransGetRateForCommodity (trans, reg_comm, split, &rate_reg);
162     DEBUG("rate_reg_ok %d and reg_comm %s", rate_reg_ok, gnc_commodity_get_fullname (reg_comm));
163 
164     /* Are we expanded */
165     expanded = gnc_tree_view_split_reg_trans_expanded (view, trans);
166 
167     if (gnc_commodity_equal (trans_curr, xfer_comm) && rate_split_ok)
168     {
169         xaccSplitSetAmount (split, amount);
170         xaccSplitSetValue (split, amount);
171         return TRUE;
172     }
173 
174     if (rate_reg_ok && rate_split_ok && !force)
175     {
176         value = gnc_numeric_div (amount, rate_reg, gnc_commodity_get_fraction (trans_curr), GNC_HOW_DENOM_REDUCE);
177         amount = gnc_numeric_mul (value, rate_split, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
178     }
179     else
180     {
181         if (!rate_split_ok)
182             rate_split = gtu_sr_get_rate_from_db (reg_comm, xfer_comm);
183 
184         /* create the exchange-rate dialog */
185 
186         xfer = gnc_xfer_dialog (GTK_WIDGET (view), NULL);
187 
188         gnc_xfer_dialog_is_exchange_dialog (xfer, &rate_split);
189 
190         /* fill in the dialog entries */
191         gnc_xfer_dialog_set_description (xfer, xaccTransGetDescription (trans));
192         gnc_xfer_dialog_set_memo (xfer, xaccSplitGetMemo (split));
193 
194         /* Get per book option */
195         gnc_xfer_dialog_set_num (xfer, gnc_get_num_action (trans, split));
196         gnc_xfer_dialog_set_date (xfer, xaccTransRetDatePosted (trans));
197 
198         value = amount;
199         if (gnc_xfer_dialog_run_exchange_dialog (xfer, &rate_split, value, reg_acc, trans, xfer_comm, expanded))
200         {
201             if (!rate_split_ok)
202                 rate_split = gnc_numeric_create (1, 1);
203             have_rate = FALSE;
204         }
205         else
206             have_rate = TRUE;
207 
208         amount = gnc_numeric_mul (value, rate_split, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
209     }
210     xaccSplitSetAmount (split, amount);
211     xaccSplitSetValue (split, value);
212 
213     LEAVE("handle_exchange_rate set split %p amt=%s; and val=%s", split, gnc_numeric_to_string (amount), gnc_numeric_to_string (value));
214     return have_rate;
215 }
216 
217 
218 /* Returns the value denom */
219 static int
gtu_sr_get_value_denom(Split * split)220 gtu_sr_get_value_denom (Split *split)
221 {
222     gnc_commodity *currency;
223     int denom;
224 
225     currency = xaccTransGetCurrency (xaccSplitGetParent (split));
226     denom = gnc_commodity_get_fraction (currency);
227     if (denom == 0)
228     {
229         gnc_commodity *commodity = gnc_default_currency ();
230         denom = gnc_commodity_get_fraction (commodity);
231         if (denom == 0)
232             denom = 100;
233     }
234     return denom;
235 }
236 
237 
238 /* Returns the amount denom */
239 static int
gtu_sr_get_amount_denom(Split * split)240 gtu_sr_get_amount_denom (Split *split)
241 {
242     int denom;
243 
244     denom = xaccAccountGetCommoditySCU (xaccSplitGetAccount (split));
245     if (denom == 0)
246     {
247         gnc_commodity *commodity = gnc_default_currency ();
248         denom = gnc_commodity_get_fraction (commodity);
249         if (denom == 0)
250             denom = 100;
251     }
252     return denom;
253 }
254 
255 
256 
257 /*###########################################################################*/
258 
259 
260 
261 /* return TRUE if we have a RATE; return FALSE if we do not. */
262 gboolean
gnc_tree_util_split_reg_has_rate(GncTreeViewSplitReg * view)263 gnc_tree_util_split_reg_has_rate (GncTreeViewSplitReg *view)
264 {
265     GncTreeModelSplitReg *model;
266 
267     model = gnc_tree_view_split_reg_get_model_from_view (view);
268 
269     switch (model->type)
270     {
271     case BANK_REGISTER2:
272     case CASH_REGISTER2:
273     case ASSET_REGISTER2:
274     case CREDIT_REGISTER2:
275     case LIABILITY_REGISTER2:
276     case INCOME_REGISTER2:
277     case EXPENSE_REGISTER2:
278     case EQUITY_REGISTER2:
279     case TRADING_REGISTER2:
280     case GENERAL_JOURNAL2:
281     case INCOME_LEDGER2:
282     case SEARCH_LEDGER2:
283         return TRUE;
284 
285     case STOCK_REGISTER2:
286     case CURRENCY_REGISTER2:
287     case PORTFOLIO_LEDGER2:
288     case RECEIVABLE_REGISTER2:
289     case PAYABLE_REGISTER2:
290     default:
291         return FALSE;
292     }
293 }
294 
295 
296 /* Is this split part of a multi split transaction */
297 gboolean
gnc_tree_util_split_reg_is_multi(Split * split)298 gnc_tree_util_split_reg_is_multi (Split *split)
299 {
300     gboolean multi = FALSE;
301     Split *osplit;
302 
303     if (!split)
304         return FALSE;
305 
306     osplit = xaccSplitGetOtherSplit (split);
307 
308     if (osplit)
309             multi = FALSE;
310     else
311     {
312         /* For multi-split transactions and stock splits,
313          * use a special value. */
314         osplit = xaccTransGetSplit (xaccSplitGetParent (split), 1);
315 
316         if (osplit)
317             multi = TRUE;
318         else if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
319             multi = TRUE;
320         else
321             multi = FALSE;
322     }
323     return multi;
324 }
325 
326 
327 /* Return the string entry for transfer column and if multi */
328 const char *
gnc_tree_util_split_reg_get_transfer_entry(Split * split,gboolean * is_multi)329 gnc_tree_util_split_reg_get_transfer_entry (Split *split, gboolean *is_multi)
330 {
331     static char *name = NULL;
332     gboolean multi = FALSE;
333 
334     Split *osplit;
335 
336     if (is_multi)
337         *is_multi = multi;
338 
339     if (!split)
340         return NULL;
341 
342     osplit = xaccSplitGetOtherSplit (split);
343 
344     g_free (name);
345 
346     if (osplit)
347         name = gnc_get_account_name_for_register (xaccSplitGetAccount (osplit));
348     else
349     {
350         /* For multi-split transactions and stock splits,
351          * use a special value. */
352         osplit = xaccTransGetSplit (xaccSplitGetParent (split), 1);
353         if (osplit)
354         {
355             name = g_strdup (SPLIT_TRANS_STR);
356             multi = TRUE;
357         }
358         else if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
359         {
360             name = g_strdup (STOCK_SPLIT_STR);
361             multi = TRUE;
362         }
363         else
364             name = g_strdup ("");
365     }
366 
367     if (is_multi)
368         *is_multi = multi;
369 
370     return name;
371 }
372 
373 
374 /* Return the string entry for transfer column when template */
375 const char *
gnc_tree_util_split_reg_template_get_transfer_entry(Split * split)376 gnc_tree_util_split_reg_template_get_transfer_entry (Split *split)
377 {
378     static char *name = NULL;
379     Account *account;
380     GncGUID *guid = NULL;
381 
382     /* Callers either g_strdup the return or use it as a temp for comparison,
383        so we keep our static ref and free it on every call. */
384     g_free (name);
385 
386     if (!split)
387         return NULL;
388     qof_instance_get (QOF_INSTANCE (split),
389 		      "sx-account", &guid,
390 		      NULL);
391     account = xaccAccountLookup (guid, gnc_get_current_book ());
392     guid_free (guid);
393     name = account ? gnc_get_account_name_for_register (account) : NULL;
394 
395     return name;
396 }
397 
398 
399 const char *
gnc_tree_util_split_reg_template_get_fdebt_entry(Split * split)400 gnc_tree_util_split_reg_template_get_fdebt_entry (Split *split)
401 {
402     gchar *formula = NULL;
403 
404     g_return_val_if_fail (split != NULL, NULL);
405     qof_instance_get (QOF_INSTANCE (split),
406 		      "sx-debit-formula", &formula,
407 		      NULL);
408 
409     return formula;
410 }
411 
412 const char *
gnc_tree_util_split_reg_template_get_fcred_entry(Split * split)413 gnc_tree_util_split_reg_template_get_fcred_entry (Split *split)
414 {
415     gchar *formula = NULL;
416 
417     g_return_val_if_fail (split != NULL, NULL);
418     qof_instance_get (QOF_INSTANCE (split),
419 		      "sx-credit-formula", &formula,
420 		      NULL);
421 
422     return formula;
423 }
424 
425 
426 gchar *
gnc_tree_util_split_reg_get_date_help(GDate * date)427 gnc_tree_util_split_reg_get_date_help (GDate *date)
428 {
429     char string[1024];
430 
431     if (g_date_valid (date))
432     {
433         struct tm tm;
434         memset (&tm, 0, sizeof (tm));
435         g_date_to_struct_tm (date, &tm);
436         qof_strftime (string, sizeof (string), _("%A %d %B %Y"), &tm);
437         return g_strdup (string);
438     }
439     else
440         return g_strdup (" ");
441 }
442 
443 
444 void
gnc_tree_util_split_reg_parse_date(GDate * parsed,const char * datestr)445 gnc_tree_util_split_reg_parse_date (GDate *parsed, const char *datestr)
446 {
447     int day, month, year;
448     gboolean use_autoreadonly = qof_book_uses_autoreadonly (gnc_get_current_book ());
449 
450     if (!parsed) return;
451     if (!datestr) return;
452 
453     if (!qof_scan_date (datestr, &day, &month, &year))
454     {
455         // Couldn't parse date, use today
456         struct tm tm_today;
457         gnc_tm_get_today_start (&tm_today);
458         day = tm_today.tm_mday;
459         month = tm_today.tm_mon + 1;
460         year = tm_today.tm_year + 1900;
461     }
462 
463     // If we have an auto-read-only threshold, do not accept a date that is
464     // older than the threshold.
465     if (use_autoreadonly)
466     {
467         GDate *d = g_date_new_dmy (day, month, year);
468         GDate *readonly_threshold = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
469         if (g_date_compare (d, readonly_threshold) < 0)
470         {
471             g_warning("Entered date %s is before the \"auto-read-only threshold\"; resetting to the threshold.", datestr);
472 #if 0
473             GtkWidget *dialog = gtk_message_dialog_new (NULL,
474                                                        0,
475                                                        GTK_MESSAGE_ERROR,
476                                                        GTK_BUTTONS_OK,
477                                                        "%s", _("Cannot store a transaction at this date"));
478             gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
479                                                      "%s", _("The entered date of the new transaction is older than the \"Read-Only Threshold\" set for this book. "
480                                                              "This setting can be changed in File->Properties->Accounts."));
481             gtk_dialog_run (GTK_DIALOG (dialog));
482             gtk_widget_destroy (dialog);
483 #endif
484 
485             // Reset the date to the threshold date
486             day = g_date_get_day (readonly_threshold);
487             month = g_date_get_month (readonly_threshold);
488             year = g_date_get_year (readonly_threshold);
489         }
490         g_date_free (d);
491         g_date_free (readonly_threshold);
492     }
493     g_date_set_dmy (parsed, day, month, year);
494 }
495 
496 
497 gboolean
gnc_tree_util_split_reg_rotate(GncTreeViewSplitReg * view,GtkTreeViewColumn * col,Transaction * trans,Split * split)498 gnc_tree_util_split_reg_rotate (GncTreeViewSplitReg *view, GtkTreeViewColumn *col, Transaction *trans, Split *split)
499 {
500     GtkCellRenderer *cr0 = NULL;
501     GList *renderers;
502     ViewCol viewcol;
503 
504     // Get the first renderer, it has the view-column value.
505     renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (col));
506     cr0 = g_list_nth_data (renderers, 0);
507     g_list_free (renderers);
508 
509     viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cr0), "view_column"));
510 
511     if (viewcol == COL_RECN)
512     {
513         const char recn_flags[] = {NREC, CREC, 0}; // List of reconciled flags
514         const gchar *flags;
515         const gchar *text;
516         gchar *this_flag;
517         gint index = 0;
518         char rec;
519 
520         flags = recn_flags;
521 
522         text = g_strdup_printf("%c", xaccSplitGetReconcile (split));
523 
524         /* Find the existing text in the list of flags */
525         this_flag = strstr (flags, text);
526 
527         if (this_flag != NULL && *this_flag != '\0')
528         {
529             /* In the list, choose the next item in the list
530                (wrapping around as necessary). */
531             index = this_flag - flags;
532 
533             if (flags[index + 1] != '\0')
534                 index = index + 1;
535             else
536                 index = 0;
537 
538             rec = recn_flags[index];
539         }
540         else
541             rec = NREC;
542 
543         gnc_tree_view_split_reg_set_dirty_trans (view, trans);
544         if (!xaccTransIsOpen (trans))
545             xaccTransBeginEdit (trans);
546 
547         xaccSplitSetReconcile (split, rec);
548         return TRUE;
549     }
550 
551     if (viewcol == COL_TYPE)
552     {
553         const char type_flags[] = {TXN_TYPE_INVOICE, TXN_TYPE_PAYMENT, 0}; // list of type flags
554         const gchar *flags;
555         const gchar *text;
556         gchar *this_flag;
557         gint index = 0;
558         char type;
559 
560         flags = type_flags;
561 
562         text = g_strdup_printf("%c", xaccTransGetTxnType (trans));
563 
564         /* Find the existing text in the list of flags */
565         this_flag = strstr (flags, text);
566 
567         if (this_flag != NULL && *this_flag != '\0')
568         {
569             /* In the list, choose the next item in the list
570                (wrapping around as necessary). */
571             index = this_flag - flags;
572 
573             if (flags[index + 1] != '\0')
574                 index = index + 1;
575             else
576                 index = 0;
577 
578             type = type_flags[index];
579         }
580         else
581             type = TXN_TYPE_NONE;
582 
583         gnc_tree_view_split_reg_set_dirty_trans (view, trans);
584         if (!xaccTransIsOpen (trans))
585             xaccTransBeginEdit (trans);
586 
587         xaccTransSetTxnType (trans, type);
588         return TRUE;
589     }
590     return FALSE;
591 }
592 
593 /*###########################################################################*/
594 
595 /* returns TRUE if you need to convert the split's value to the local
596  * (account) display currency.  Returns FALSE if you can just use the
597  * split->value directly.
598  */
599 gboolean
gnc_tree_util_split_reg_needs_conv_rate(GncTreeViewSplitReg * view,Transaction * trans,Account * acc)600 gnc_tree_util_split_reg_needs_conv_rate (GncTreeViewSplitReg *view,
601                                     Transaction *trans, Account *acc)
602 {
603     gnc_commodity *trans_cur, *acc_com;
604 
605     /* If there is not a RATE_CELL, then don't do anything */
606     if (!gnc_tree_util_split_reg_has_rate (view))
607         return FALSE;
608 
609     /* if txn->currency == acc->commodity, then return FALSE */
610     acc_com = xaccAccountGetCommodity (acc);
611     trans_cur = xaccTransGetCurrency (trans);
612     if (trans_cur && acc_com && gnc_commodity_equal (trans_cur, acc_com))
613         return FALSE;
614 
615     return TRUE;
616 }
617 
618 
619 gboolean
gnc_tree_util_split_reg_needs_amount(GncTreeViewSplitReg * view,Split * split)620 gnc_tree_util_split_reg_needs_amount (GncTreeViewSplitReg *view, Split *split)
621 {
622     Transaction *txn = xaccSplitGetParent (split);
623     Account *acc = xaccSplitGetAccount (split);
624 
625     return gnc_tree_util_split_reg_needs_conv_rate (view, txn, acc);
626 }
627 
628 /*###########################################################################*/
629 
630 gnc_numeric
gnc_tree_util_split_reg_get_value_for(GncTreeViewSplitReg * view,Transaction * trans,Split * split,gboolean is_blank)631 gnc_tree_util_split_reg_get_value_for (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gboolean is_blank)
632 {
633     gnc_numeric        ret_num;
634     GNCPrintAmountInfo ret_print_info;
635 
636     if (gnc_tree_util_split_reg_get_debcred_entry (view, trans, split, is_blank, &ret_num, &ret_print_info))
637         return ret_num;
638     else
639         return gnc_numeric_zero();
640 }
641 
642 
643 gboolean
gnc_tree_util_split_reg_get_debcred_entry(GncTreeViewSplitReg * view,Transaction * trans,Split * split,gboolean is_blank,gnc_numeric * ret_num,GNCPrintAmountInfo * ret_print_info)644 gnc_tree_util_split_reg_get_debcred_entry (GncTreeViewSplitReg *view,
645                                       Transaction *trans, Split *split,
646                                       gboolean is_blank, gnc_numeric *ret_num,
647                                       GNCPrintAmountInfo *ret_print_info)
648 
649 {
650     GncTreeModelSplitReg *model;
651     gnc_commodity *currency;
652 
653     model = gnc_tree_view_split_reg_get_model_from_view (view);
654 
655     currency = xaccTransGetCurrency (trans);
656     if (!currency)
657         currency = gnc_default_currency ();
658 
659     if (is_blank)
660     {
661         gnc_numeric imbalance;
662         Account *acc;
663 
664         imbalance = xaccTransGetImbalanceValue (trans);
665 
666         if (gnc_numeric_zero_p (imbalance))
667             return FALSE;
668 
669         if (xaccTransUseTradingAccounts (trans))
670         {
671             MonetaryList *imbal_list;
672             gnc_monetary *imbal_mon;
673             imbal_list = xaccTransGetImbalance (trans);
674 
675             if (!imbal_list)
676             {
677                 /* No commodity imbalance, there shouldn't be a value imablance. */
678                 return FALSE;
679             }
680 
681             if (imbal_list->next)
682             {
683                 /* Multiple currency imbalance. */
684                 gnc_monetary_list_free (imbal_list);
685                 return FALSE;
686             }
687 
688             imbal_mon = imbal_list->data;
689             if (!gnc_commodity_equal (gnc_monetary_commodity (*imbal_mon), currency))
690             {
691                 /* Imbalance is in wrong currency */
692                 gnc_monetary_list_free (imbal_list);
693                 return FALSE;
694             }
695 
696             if (!gnc_numeric_equal (gnc_monetary_value (*imbal_mon), imbalance))
697             {
698                 /* Value and commodity imbalances differ */
699                 gnc_monetary_list_free (imbal_list);
700                 return FALSE;
701             }
702 
703             /* Done with the imbalance list */
704             gnc_monetary_list_free (imbal_list);
705         }
706 
707         imbalance = gnc_numeric_neg (imbalance);
708 
709         acc = gnc_tree_model_split_reg_get_anchor (model);
710 
711         if (gnc_tree_util_split_reg_needs_conv_rate (view, trans, acc))
712         {
713             imbalance = gnc_numeric_mul (imbalance,
714                                          xaccTransGetAccountConvRate (trans, acc),
715                                          gnc_commodity_get_fraction (currency),
716                                          GNC_HOW_RND_ROUND_HALF_UP);
717         }
718         else
719         {
720             imbalance = gnc_numeric_convert (imbalance,
721                                              gnc_commodity_get_fraction (currency),
722                                              GNC_HOW_RND_ROUND_HALF_UP);
723         }
724 
725         *ret_num = imbalance;
726         *ret_print_info = gnc_account_print_info (acc, FALSE);
727          return TRUE;
728     }
729 
730     {
731         gnc_numeric amount;
732         gnc_commodity *split_commodity;
733         GNCPrintAmountInfo print_info;
734         Account *account;
735         gnc_commodity *commodity;
736 
737         account = gnc_tree_model_split_reg_get_anchor (model);
738 
739         commodity = xaccAccountGetCommodity (account);
740         split_commodity = xaccAccountGetCommodity (xaccSplitGetAccount (split));
741 
742         if (xaccTransUseTradingAccounts (trans))
743         {
744             gboolean use_symbol, is_current = FALSE;
745             Split *current_split = gnc_tree_view_split_reg_get_current_split (view);
746             RowDepth depth = gnc_tree_view_reg_get_selected_row_depth (view);
747 
748             if ((split == current_split) && (depth == SPLIT3))
749                 is_current = TRUE;
750 
751             if (model->type == STOCK_REGISTER2 ||
752                     model->type == CURRENCY_REGISTER2 ||
753                     model->type == PORTFOLIO_LEDGER2)
754             {
755                 gnc_commodity *amount_commodity;
756                 /* security register.  If this split has price and shares columns,
757                    use the value, otherwise use the amount.  */
758                 if (gtu_sr_use_security (view))
759                 {
760                     amount = xaccSplitGetValue (split);
761                     amount_commodity = currency;
762                 }
763                 else
764                 {
765                     amount = xaccSplitGetAmount (split);
766                     amount_commodity = split_commodity;
767                 }
768                 /* Show the currency if it is not the default currency */
769                 if (is_current ||
770                         gnc_commodity_equiv (amount_commodity, gnc_default_currency ()))
771                     use_symbol = FALSE;
772                 else
773                     use_symbol = TRUE;
774                 print_info = gnc_commodity_print_info (amount_commodity, use_symbol);
775             }
776             else
777             {
778                 /* non-security register, always use the split amount. */
779                 amount = xaccSplitGetAmount (split);
780                 if (is_current ||
781                         gnc_commodity_equiv (split_commodity, commodity))
782                     use_symbol = FALSE;
783                 else
784                     use_symbol = TRUE;
785                 print_info = gnc_commodity_print_info (split_commodity, use_symbol);
786             }
787         }
788         else
789         {
790             /* If this account is not a stock/mutual/currency account, and
791             * currency != the account commodity, then use the SplitAmount
792             * instead of the SplitValue.
793             */
794             switch (model->type)
795             {
796             case STOCK_REGISTER2:
797             case CURRENCY_REGISTER2:
798             case PORTFOLIO_LEDGER2:
799                 amount = xaccSplitGetValue (split);
800                 print_info = gnc_commodity_print_info (currency, FALSE);
801                 break;
802 
803             default:
804                 if (commodity && !gnc_commodity_equal (commodity, currency))
805                     /* Convert this to the "local" value */
806                     amount = xaccSplitConvertAmount (split, account);
807                 else
808                     amount = xaccSplitGetValue (split);
809                 print_info = gnc_account_print_info (account, FALSE);
810                 break;
811             }
812         }
813 
814         if (gnc_numeric_zero_p (amount))
815             return FALSE;
816 
817         *ret_num = amount;
818         *ret_print_info = print_info;
819          return TRUE;
820     }
821 }
822 
823 /*###########################################################################*/
824 
825 void
gnc_tree_util_split_reg_set_value_for(GncTreeViewSplitReg * view,Transaction * trans,Split * split,gnc_numeric input,gboolean force)826 gnc_tree_util_split_reg_set_value_for (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input, gboolean force)
827 {
828 //    GncTreeModelSplitReg *model;
829     GtkWindow *window;
830 //    Account *anchor;
831 //    Account *acct = xaccSplitGetAccount (split);
832 //    gnc_commodity *currency;
833 
834     ENTER("set_value_for trans %p and split %p input %s force %d", trans, split, gnc_numeric_to_string (input), force);
835 
836 //    currency = xaccTransGetCurrency (trans);
837 
838 //    model = gnc_tree_view_split_reg_get_model_from_view (view);
839 
840 //    anchor = gnc_tree_model_split_reg_get_anchor (model);
841 
842     if (gnc_numeric_zero_p (input))
843     {
844         xaccSplitSetValue (split, input);
845         xaccSplitSetAmount (split, input);
846         LEAVE("input is zero");
847         return;
848     }
849 
850     window = gnc_ui_get_main_window (GTK_WIDGET (view));
851 
852     if (gtu_sr_needs_exchange_rate (view, trans, split))
853     {
854         if (gtu_sr_handle_exchange_rate (view, input, trans, split, force))
855         {
856             ; //FIXME ??????
857         }
858         else
859         {
860             gnc_error_dialog (window, "%s",
861                          _("Exchange Rate Canceled, using existing rate or default 1 to 1 rate if this is a new transaction."));
862         }
863         LEAVE("used exchange rate");
864         return;
865     }
866 
867     gnc_tree_util_split_reg_save_amount_values (view, trans, split, input);
868 
869     LEAVE(" ");
870 }
871 
872 void
gnc_tree_util_split_reg_save_amount_values(GncTreeViewSplitReg * view,Transaction * trans,Split * split,gnc_numeric input)873 gnc_tree_util_split_reg_save_amount_values (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input)
874 {
875     GncTreeModelSplitReg *model;
876     Account *acc;
877     gnc_numeric new_amount, convrate, amtconv, value;
878     gnc_commodity *curr, *reg_com, *xfer_com;
879     Account *xfer_acc;
880 
881     ENTER("View is %p, trans is %p, split is %p, input is %s", view, trans, split, gnc_numeric_to_string (input));
882 
883     model = gnc_tree_view_split_reg_get_model_from_view (view);
884 
885     new_amount = input;
886 
887     acc = gnc_tree_model_split_reg_get_anchor (model);
888 
889     xfer_acc = xaccSplitGetAccount (split);
890     xfer_com = xaccAccountGetCommodity (xfer_acc);
891     reg_com = xaccAccountGetCommodity (acc);
892     curr = xaccTransGetCurrency (trans);
893 
894     if (!xaccTransGetRateForCommodity (trans, reg_com, NULL, &convrate))
895         convrate = gnc_numeric_create (100, 100);
896 
897     amtconv = convrate;
898 
899     if (gnc_tree_util_split_reg_needs_conv_rate (view, trans, acc))
900     {
901 
902         /* If we are in an expanded register and the xfer_acc->comm !=
903         * reg_acc->comm then we need to compute the convrate here.
904         * Otherwise, we _can_ use the rate_cell!
905         */
906         if (gnc_commodity_equal (reg_com, xfer_com))
907             amtconv = xaccTransGetAccountConvRate (trans, acc);
908     }
909 
910     if (xaccTransUseTradingAccounts (trans))
911     {
912         /* Using currency accounts, the amount is probably really the
913            amount and not the value. */
914         gboolean is_amount;
915 
916         if (model->type == STOCK_REGISTER2 ||
917                 model->type == CURRENCY_REGISTER2 ||
918                 model->type == PORTFOLIO_LEDGER2)
919         {
920             if (xaccAccountIsPriced (xfer_acc) ||
921                     !gnc_commodity_is_iso (xaccAccountGetCommodity (xfer_acc)))
922                 is_amount = FALSE;
923             else
924                 is_amount = TRUE;
925         }
926         else
927         {
928             is_amount = TRUE;
929         }
930 
931         if (is_amount)
932         {
933             xaccSplitSetAmount (split, new_amount);
934             if (gnc_tree_util_split_reg_needs_amount (view, split))
935             {
936                 value = gnc_numeric_div (new_amount, amtconv,
937                                         gnc_commodity_get_fraction (curr),
938                                         GNC_HOW_RND_ROUND_HALF_UP);
939                 xaccSplitSetValue (split, value);
940             }
941             else
942                 xaccSplitSetValue (split, new_amount);
943         }
944         else
945         {
946             xaccSplitSetValue (split, new_amount);
947         }
948         LEAVE(" ");
949         return;
950     }
951 
952     /* How to interpret new_amount depends on our view of this
953      * transaction.  If we're sitting in an account with the same
954      * commodity as the transaction, then we can set the Value and then
955      * compute the amount.  Otherwise we are setting the "converted
956      * value".  This means we need to convert new_amount to the actual
957      * 'value' by dividing by the convrate in order to set the value.
958      */
959 
960     /* Now compute/set the split value.  Amount is in the register
961      * currency but we need to convert to the txn currency.
962      */
963     if (gnc_tree_util_split_reg_needs_conv_rate (view, trans, acc))
964     {
965         /* convert the amount to the Value ... */
966         value = gnc_numeric_div (new_amount, amtconv,
967                                  gnc_commodity_get_fraction (curr),
968                                  GNC_HOW_RND_ROUND_HALF_UP);
969         xaccSplitSetValue (split, value);
970     }
971     else
972     {
973         xaccSplitSetValue (split, new_amount);
974     }
975 
976     /* Now re-compute the Amount from the Value.  We may need to convert
977      * from the Value back to the amount here using the convrate from
978      * earlier.
979      */
980     value = xaccSplitGetValue (split);
981 
982     if (gnc_tree_util_split_reg_needs_amount (view, split))
983     {
984         acc = xaccSplitGetAccount (split);
985         new_amount = gnc_numeric_mul (value, convrate,
986                                       xaccAccountGetCommoditySCU (acc),
987                                       GNC_HOW_RND_ROUND_HALF_UP);
988         xaccSplitSetAmount (split, new_amount);
989     }
990     else
991     {
992         xaccSplitSetAmount (split, value);
993     }
994     LEAVE(" ");
995 }
996 
997 /*###########################################################################*/
998 
999 /* Takes the input with column and sets the price / amount / value so they are consistent */
1000 void
gnc_tree_util_set_number_for_input(GncTreeViewSplitReg * view,Transaction * trans,Split * split,gnc_numeric input,gint viewcol)1001 gnc_tree_util_set_number_for_input (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input, gint viewcol)
1002 {
1003     GncTreeModelSplitReg *model;
1004     gnc_numeric  price;
1005     gnc_numeric  amount;
1006     gnc_numeric  value;
1007 
1008     gboolean price_changed = FALSE;   // Price of each share
1009     gboolean value_changed = FALSE;   // Total value of shares
1010     gboolean amount_changed = FALSE;  // No of shares
1011 
1012     gboolean recalc_amount = FALSE;
1013     gboolean recalc_price = FALSE;
1014     gboolean recalc_value = FALSE;
1015     gboolean expanded = FALSE;
1016     int denom;
1017     Account *account = NULL;
1018 
1019     ENTER("trans %p and split %p and input is %s and viewcol is %d", trans, split, gnc_numeric_to_string (input), viewcol);
1020 
1021     model = gnc_tree_view_split_reg_get_model_from_view (view);
1022 
1023     /* Check for sub account view */
1024     if (!gnc_tree_model_split_reg_get_sub_account (model))
1025         account = gnc_tree_model_split_reg_get_anchor (model);
1026 
1027     expanded = gnc_tree_view_split_reg_trans_expanded (view, trans);
1028 
1029     if (!account)
1030         account = xaccSplitGetAccount (split);
1031 
1032     if (!xaccAccountIsPriced (account))
1033         return;
1034 
1035     /* If we are using commodity trading accounts then the value may
1036        not really be the value.  Punt if so. */
1037     if (xaccTransUseTradingAccounts (xaccSplitGetParent (split)))
1038     {
1039         gnc_commodity *acc_commodity;
1040         acc_commodity = xaccAccountGetCommodity (account);
1041         if (!(xaccAccountIsPriced (account) || !gnc_commodity_is_iso (acc_commodity)))
1042             return;
1043     }
1044 
1045     if (gnc_numeric_zero_p (input))
1046     {
1047         xaccSplitSetValue (split, input);
1048         xaccSplitSetAmount (split, input);
1049         LEAVE("zero");
1050         return;
1051     }
1052 
1053     amount = xaccSplitGetAmount (split);
1054     value = xaccSplitGetValue (split);
1055 
1056     if (viewcol == COL_AMTVAL && !expanded)
1057     {
1058         value_changed = TRUE;
1059         if (gnc_numeric_zero_p (amount))
1060         {
1061             xaccSplitSetValue (split, input);
1062             xaccSplitSetAmount (split, input);
1063             LEAVE("");
1064             return;
1065         }
1066     }
1067     else if (viewcol == COL_AMTVAL && expanded)
1068     {
1069         amount_changed = TRUE;
1070         if (gnc_numeric_zero_p (value))
1071         {
1072             xaccSplitSetValue (split, input);
1073             xaccSplitSetAmount (split, input);
1074             LEAVE("");
1075             return;
1076         }
1077     }
1078 
1079     if (viewcol == COL_PRICE)
1080     {
1081         price_changed = TRUE;
1082         if (gnc_numeric_zero_p (value))
1083         {
1084             amount = gnc_numeric_create (1,1);
1085             xaccSplitSetValue (split, input);
1086             xaccSplitSetAmount (split, amount);
1087             LEAVE("");
1088             return;
1089         }
1090     }
1091 
1092     if ((viewcol == COL_CREDIT || viewcol == COL_DEBIT) && !expanded)
1093     {
1094         amount_changed = TRUE;
1095         if (gnc_numeric_zero_p (value))
1096         {
1097             xaccSplitSetValue (split, input);
1098             xaccSplitSetAmount (split, input);
1099             LEAVE("");
1100             return;
1101         }
1102     }
1103     else if ((viewcol == COL_CREDIT || viewcol == COL_DEBIT) && expanded)
1104     {
1105         value_changed = TRUE;
1106         if (gnc_numeric_zero_p (value))
1107         {
1108             xaccSplitSetValue (split, input);
1109             xaccSplitSetAmount (split, input);
1110             LEAVE("");
1111             return;
1112         }
1113     }
1114 
1115     DEBUG("value_changed %d, price_changed %d, amount_changed %d", value_changed, price_changed, amount_changed);
1116 
1117     {
1118         int choice;
1119         int default_value;
1120         GList *node;
1121         GList *radio_list = NULL;
1122         const char *title = _("Recalculate Transaction");
1123         const char *message = _("The values entered for this transaction "
1124                                 "are inconsistent. Which value would you "
1125                                 "like to have recalculated?");
1126 
1127         if (amount_changed)
1128             radio_list = g_list_append (radio_list,
1129                                         g_strdup_printf ("%s (%s)",
1130                                                 _("_Shares"), _("Changed")));
1131         else
1132             radio_list = g_list_append (radio_list, g_strdup (_("_Shares")));
1133 
1134         if (price_changed)
1135             radio_list = g_list_append (radio_list,
1136                                         g_strdup_printf ("%s (%s)",
1137                                                 _("_Price"), _("Changed")));
1138         else
1139             radio_list = g_list_append (radio_list, g_strdup (_("_Price")));
1140 
1141         if (value_changed)
1142             radio_list = g_list_append (radio_list,
1143                                         g_strdup_printf ("%s (%s)",
1144                                                 _("_Value"), _("Changed")));
1145         else
1146             radio_list = g_list_append (radio_list, g_strdup (_("_Value")));
1147 
1148         if(expanded)
1149         {
1150             if (price_changed)
1151                 default_value = 2;  /* change the value */
1152             else
1153                 default_value = 1;  /* change the price */
1154         }
1155         else
1156         {
1157             if (price_changed)
1158                 default_value = 0;  /* change the amount / shares */
1159             else
1160                 default_value = 1;  /* change the price */
1161         }
1162         choice = gnc_choose_radio_option_dialog
1163                  (gnc_tree_view_split_reg_get_parent (view),
1164                   title,
1165                   message,
1166                   _("_Recalculate"),
1167                   default_value,
1168                   radio_list);
1169 
1170         for (node = radio_list; node; node = node->next)
1171             g_free (node->data);
1172 
1173         g_list_free (radio_list);
1174 
1175         switch (choice)
1176         {
1177         case 0: /* Modify number of shares */
1178             recalc_amount = TRUE;
1179             break;
1180         case 1: /* Modify the share price */
1181             recalc_price = TRUE;
1182             break;
1183         case 2: /* Modify total value */
1184             recalc_value = TRUE;
1185             break;
1186         default: /* Cancel */
1187             LEAVE(" " );
1188             return;
1189         }
1190     }
1191 
1192     DEBUG("recalc_value %d, recalc_price %d, recalc_amount %d", recalc_value, recalc_price, recalc_amount);
1193 
1194     if (recalc_amount)
1195     {
1196         denom = gtu_sr_get_amount_denom (split);
1197 
1198         if (amount_changed)
1199         {
1200             LEAVE("");
1201             return;
1202         }
1203 
1204         if (price_changed)
1205             price = input;
1206         else
1207             price = gnc_numeric_div (value, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
1208 
1209         if (value_changed)
1210         {
1211             xaccSplitSetValue (split, input);
1212             amount = gnc_numeric_div (input, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
1213             xaccSplitSetAmount (split, amount);
1214         }
1215         else
1216         {
1217             amount = gnc_numeric_div (value, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
1218             xaccSplitSetAmount (split, amount);
1219         }
1220     }
1221 
1222     if (recalc_price)
1223     {
1224         if (price_changed)
1225         {
1226             LEAVE("");
1227             return;
1228         }
1229 
1230         if (amount_changed)
1231         {
1232             xaccSplitSetAmount (split, input);
1233             xaccSplitSetValue (split, value);
1234         }
1235 
1236         if (value_changed)
1237         {
1238             xaccSplitSetValue (split, input);
1239             xaccSplitSetAmount (split, amount);
1240         }
1241     }
1242 
1243     if (recalc_value)
1244     {
1245         denom = gtu_sr_get_value_denom (split);
1246 
1247         if (value_changed)
1248         {
1249             LEAVE("");
1250             return;
1251         }
1252 
1253         if (price_changed)
1254             price = input;
1255         else
1256             price = gnc_numeric_div (value, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
1257 
1258         if (amount_changed)
1259         {
1260             xaccSplitSetAmount (split, input);
1261             value = gnc_numeric_mul (input, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
1262             xaccSplitSetValue (split, value);
1263         }
1264         else
1265         {
1266             value = gnc_numeric_mul (amount, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
1267             xaccSplitSetValue (split, value);
1268         }
1269     }
1270 
1271     /* If the number of splits is two, change other split to balance */
1272     if (!gnc_tree_util_split_reg_is_multi (split) && expanded)
1273     {
1274         Split *osplit;
1275         gnc_commodity *osplit_com;
1276 
1277         osplit = xaccSplitGetOtherSplit (split);
1278 
1279         value = xaccSplitGetValue (split);
1280 
1281         osplit_com = xaccAccountGetCommodity (xaccSplitGetAccount (osplit));
1282 
1283         if (gnc_commodity_is_currency (osplit_com))
1284         {
1285             xaccSplitSetValue (osplit, gnc_numeric_neg (value));
1286             xaccSplitSetAmount (osplit, gnc_numeric_neg (value));
1287         }
1288     }
1289     LEAVE("");
1290 }
1291 
1292 
1293 /* Set the value for the given input amount */
1294 void
gnc_tree_util_set_value_for_amount(GncTreeViewSplitReg * view,Transaction * trans,Split * split,gnc_numeric input)1295 gnc_tree_util_set_value_for_amount (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input)
1296 {
1297     gnc_numeric  split_rate;
1298     gnc_numeric  amount;
1299     gnc_numeric  value, new_value;
1300     int denom;
1301 
1302     ENTER("trans %p and split %p and input is %s", trans, split, gnc_numeric_to_string (input));
1303 
1304     if (gnc_numeric_zero_p (input))
1305     {
1306         xaccSplitSetValue (split, input);
1307         xaccSplitSetAmount (split, input);
1308         LEAVE("zero");
1309         return;
1310     }
1311 
1312     amount = xaccSplitGetAmount (split);
1313     value = xaccSplitGetValue (split);
1314 
1315     denom = gtu_sr_get_value_denom (split);
1316 
1317     split_rate = gnc_numeric_div (value, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
1318     if (gnc_numeric_check (split_rate) != GNC_ERROR_OK)
1319         split_rate = gnc_numeric_create (100,100);
1320 
1321     new_value = gnc_numeric_mul (input, split_rate, denom, GNC_HOW_RND_ROUND_HALF_UP);
1322 
1323     xaccSplitSetValue (split, new_value);
1324     xaccSplitSetAmount (split, input);
1325 
1326     LEAVE("");
1327 }
1328 
1329 
1330 /* Get the rate */
1331 gnc_numeric
gnc_tree_util_get_rate_for(GncTreeViewSplitReg * view,Transaction * trans,Split * split,gboolean is_blank)1332 gnc_tree_util_get_rate_for (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gboolean is_blank)
1333 {
1334     gnc_numeric num;
1335 
1336     ENTER("trans %p and split %p is_blank %d", trans, split, is_blank);
1337 
1338     num = gnc_tree_util_split_reg_get_value_for (view, trans, split, is_blank);
1339 //FIXME Not sure about this...
1340     if (xaccTransUseTradingAccounts (trans))
1341         num = gnc_numeric_div (num, xaccSplitGetValue (split), GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
1342     else
1343         num = gnc_numeric_div (xaccSplitGetAmount (split), num, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
1344 
1345     LEAVE("split %p and return num is %s", split, gnc_numeric_to_string (num));
1346     return num;
1347 }
1348 
1349 
1350 /*****************************************************************************/
1351