GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
assistant-loan.c
1 /********************************************************************\
2  * assistant-loan.c : An Assistant for setting up loan-repayment *
3  * scheduled transactions. *
4  * Copyright (C) 2002,2007 Joshua Sled <[email protected]> *
5  * Copyright (C) 2006 David Hampton <[email protected]> *
6  * Copyright (C) 2011 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 [email protected] *
24 \********************************************************************/
25 
26 #include "config.h"
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <math.h>
32 #include "assistant-loan.h"
33 #include "SchedXaction.h"
34 #include "SX-book.h"
35 #include "SX-ttinfo.h"
36 #include "assistant-utils.h"
37 #include "gnc-amount-edit.h"
38 #include "gnc-account-sel.h"
39 #include "gnc-date.h"
40 #include "gnc-exp-parser.h"
41 #include "gnc-component-manager.h"
42 #include "dialog-utils.h"
43 #include "Account.h"
44 #include "gnc-ui.h"
45 #include "gnc-gdate-utils.h"
46 #include "gnc-gui-query.h"
47 #include "gnc-ui-util.h"
48 #include "gnc-frequency.h"
49 #include "gnc-engine.h"
50 
51 #ifndef HAVE_STRFMON
52 # include "strfmon.h"
53 #else
54 # include <monetary.h>
55 #endif
56 #define DIALOG_LOAN_ASSISTANT_CM_CLASS "assistant-loan-setup"
57 
58 static QofLogModule log_module = GNC_MOD_ASSISTANT;
59 
60 enum loan_cols
61 {
62  LOAN_COL_DATE = 0,
63  LOAN_COL_PAYMENT,
64  LOAN_COL_PRINCIPAL,
65  LOAN_COL_INTEREST,
66  NUM_LOAN_COLS
67 };
68 
69 typedef enum
70 {
71  CURRENT_YEAR,
72  NOW_PLUS_ONE,
73  WHOLE_LOAN,
74  CUSTOM
75 } REV_RANGE_OPTS;
76 
77 struct LoanAssistantData_;
78 
83 typedef struct RepayOptData_
84 {
85  gboolean enabled;
86  gboolean optValid;
87  gboolean FreqUniq;
88  char *name; /* { "insurance", "pmi", "taxes", ... } */
89  char *txnMemo;
90  float amount;
91  gboolean throughEscrowP;
92  gboolean specSrcAcctP;
93  Account *to;
94  Account *from; /* If NULL { If throughEscrowP, then through escrowAcct };
95  * else: undefined. */
96  GList *schedule;
97  /* If NULL, part of repayment; otherwise: defined
98  * here. */
99  GDate *startDate;
100 } RepayOptData;
101 
105 typedef struct RepayOptDataDefault_
106 {
107  char *name;
108  char *defaultTxnMemo;
109  gboolean escrowDefault;
110  gboolean specSrcAcctDefault;
112 
113 static RepayOptDataDefault REPAY_DEFAULTS[] =
114 {
115  /* { name, default txn memo, throughEscrowP, specSrcAcctP } */
116  { N_("Taxes"), N_("Tax Payment"), TRUE, FALSE },
117  { N_("Insurance"), N_("Insurance Payment"), TRUE, FALSE },
118  /* Translators: PMI stands for Private Mortgage Insurance. */
119  { N_("PMI"), N_("PMI Payment"), TRUE, FALSE },
120  { N_("Other Expense"), N_("Miscellaneous Payment"), FALSE, FALSE },
121  { NULL }
122 };
123 
127 typedef struct RepayOptUI_
128 {
129  /* must be stated this way [instead of 'LoanAssistantData*'] because of
130  * forward decl. */
131  struct LoanAssistantData_ *ldd;
132  GtkCheckButton *optCb;
133  GtkCheckButton *escrowCb;
134  RepayOptData *optData;
136 
137 typedef enum
138 {
139  GNC_FIXED = 0,
140  GNC_VARIABLE,
141  GNC_VARIABLE_3_1 = GNC_VARIABLE,
142  GNC_VARIABLE_5_1,
143  GNC_VARIABLE_7_1,
144  GNC_VARIABLE_10_1,
145  /* ... FIXME */
146 } LoanType;
147 
148 typedef enum
149 {
150  GNC_MONTHS = 0,
151  GNC_YEARS
152 } PeriodSize;
153 
154 /*type of interest rate entered*/
155 typedef enum
156 {
157  GNC_IRATE_SIMPLE,
158  GNC_IRATE_APR_DAILY,
159  GNC_IRATE_APR_WEEKLY,
160  GNC_IRATE_APR_MONTHLY,
161  GNC_IRATE_APR_QUARTERLY,
162  GNC_IRATE_APR_ANNUALLY
163 } IRateType;
164 
170 typedef struct rev_repayment_row
171 {
172  GDate date;
173  gnc_numeric *numCells;
175 
179 typedef struct LoanData_
180 {
181  Account *primaryAcct;
182  gnc_numeric principal;
183  float interestRate;
184  IRateType rateType;
185  LoanType type;
186  GList *loan_schedule;
187  GDate *startDate;
188  GDate *varStartDate;
189  int numPer;
190  PeriodSize perSize;
191  int numMonRemain;
192 
193  char *repMemo;
194  char *repAmount;
195  Account *repFromAcct;
196  Account *repPriAcct;
197  Account *repIntAcct;
198  Account *escrowAcct;
199  GList *repayment_schedule;
200  GDate *repStartDate;
201 
202  int repayOptCount;
203  RepayOptData **repayOpts;
204 
205  /* Data concerning the review of repayments. */
206  int revNumPmts;
207  int revRepayOptToColMap[ (sizeof(REPAY_DEFAULTS)
208  / sizeof(RepayOptDataDefault))
209  - 1 ];
210  GList *revSchedule;
211 } LoanData;
212 
216 typedef struct LoanAssistantData_
217 {
218  GtkWidget *window;
219  GtkWidget *assistant;
220 
221  LoanData ld;
222  /* The UI-side storage of repayment data; this is 1:1 with the array
223  * in LoanData */
224  RepayOptUIData **repayOptsUI;
225 
226  /* Current index of the payment opt for multiplexing the 'payment'
227  * page. */
228  int currentIdx;
229 
230  /* widgets */
231  /* prm = params */
232  GtkTable *prmTable;
233  GNCAccountSel *prmAccountGAS;
234  GNCAmountEdit *prmOrigPrincGAE;
235  GtkSpinButton *prmIrateSpin;
236  GtkComboBox *prmType;
237  GtkFrame *prmVarFrame;
238  GncFrequency *prmVarGncFreq;
239  GNCDateEdit *prmStartDateGDE;
240  GtkSpinButton *prmLengthSpin;
241  GtkComboBox *prmLengthType;
242  GtkSpinButton *prmRemainSpin;
243  GtkComboBox *prmIrateType;
244 
245  /* opt = options */
246  GtkVBox *optVBox;
247  GtkCheckButton *optEscrowCb;
248  GtkHBox *optEscrowHBox;
249  GNCAccountSel *optEscrowGAS;
250 
251  /* rep = repayment */
252  GtkEntry *repTxnName;
253  GtkTable *repTable;
254  GtkEntry *repAmtEntry;
255  GNCAccountSel *repAssetsFromGAS;
256  GNCAccountSel *repPrincToGAS;
257  GNCAccountSel *repIntToGAS;
258  GtkFrame *repFreqFrame;
259  GncFrequency *repGncFreq;
260 
261  /* pay = payment[s] */
262  GtkEntry *payTxnName;
263  GtkEntry *payAmtEntry;
264  GNCAccountSel *payAcctFromGAS;
265  GNCAccountSel *payAcctEscToGAS;
266  GNCAccountSel *payAcctEscFromGAS;
267  GNCAccountSel *payAcctToGAS;
268  GtkTable *payTable;
269  GtkCheckButton *payUseEscrow;
270  GtkCheckButton *paySpecSrcAcct;
271  GtkLabel *payAcctFromLabel;
272  GtkLabel *payEscToLabel;
273  GtkLabel *payEscFromLabel;
274  GtkRadioButton *payTxnFreqPartRb;
275  GtkRadioButton *payTxnFreqUniqRb;
276  GtkAlignment *payFreqAlign;
277  GncFrequency *payGncFreq;
278 
279  /* rev = review */
280  GtkComboBox *revRangeOpt;
281  GtkFrame *revDateFrame;
282  GtkTable *revTable;
283  GNCDateEdit *revStartDate;
284  GNCDateEdit *revEndDate;
285  GtkScrolledWindow *revScrollWin;
286  GtkTreeView *revView;
288 
292 typedef struct toCreateSX_
293 {
295  gchar *name;
297  GDate start, last, end;
299  GList *schedule;
301  gint instNum;
306 } toCreateSX;
307 
308 /**************************************************************************/
309 
310 static void loan_assistant_window_destroy_cb( GtkObject *object, gpointer user_data );
311 static void loan_assistant_close_handler( gpointer user_data );
312 static void loan_assistant_data_init( LoanAssistantData *ldd );
313 
314 static void loan_info_prep( GtkAssistant *assistant, gpointer user_data );
315 static void loan_info_prm_type_cb( GtkWidget *w, gpointer user_data );
316 static void loan_info_calc_update_cb( GtkWidget *widget, gpointer user_data );
317 void loan_info_page_valid_cb( GtkWidget *widget, gpointer user_data );
318 static gboolean loan_info_page_complete( GtkAssistant *assistant, gpointer user_data );
319 static void loan_info_page_save( GtkAssistant *assistant, gpointer user_data );
320 
321 static void loan_opt_prep( GtkAssistant *assistant, gpointer user_data );
322 static void loan_opt_toggled_cb( GtkToggleButton *tb, gpointer user_data );
323 static void loan_opt_consistency_cb( GtkToggleButton *tb, gpointer user_data );
324 static void loan_opt_escrow_toggle_cb( GtkToggleButton *tb, gpointer user_data );
325 static void loan_opt_escrow_toggled_cb( GtkToggleButton *tb, gpointer user_data );
326 void loan_opt_page_valid_cb (GtkWidget *widget, gpointer user_data );
327 static gboolean loan_opt_page_complete( GtkAssistant *assistant, gpointer user_data );
328 
329 static void loan_rep_prep ( GtkAssistant *assistant, gpointer user_data );
330 void loan_rep_page_valid_cb (GtkWidget *widget, gpointer user_data );
331 static gboolean loan_rep_page_complete( GtkAssistant *assistant, gpointer user_data );
332 static void loan_rep_page_save( GtkAssistant *assistant, gpointer user_data );
333 
334 static void loan_pay_prep ( GtkAssistant *assistant, gpointer user_data );
335 static void loan_pay_use_esc_setup( LoanAssistantData *ldd, gboolean newState );
336 static void loan_pay_use_esc_toggle_cb( GtkToggleButton *tb, gpointer user_data );
337 static void loan_pay_spec_src_setup( LoanAssistantData *ldd, gboolean newState );
338 static void loan_pay_spec_src_toggle_cb( GtkToggleButton *tb, gpointer user_data );
339 static void loan_pay_freq_toggle_cb( GtkToggleButton *tb, gpointer user_data );
340 static void loan_pay_page_valid_cb (GtkWidget *widget, gpointer user_data );
341 static gboolean loan_pay_complete( GtkAssistant *assistant, gpointer user_data );
342 static gboolean loan_pay_all_opt_valid ( GtkAssistant *assistant, gpointer user_data );
343 static void loan_pay_back_button_cb( GtkButton *button, gpointer user_data );
344 static void loan_pay_next_button_cb( GtkButton *button, gpointer user_data );
345 
346 static void loan_rev_prep ( GtkAssistant *assistant, gpointer user_data );
347 static void loan_rev_recalc_schedule( LoanAssistantData *ldd );
348 static void loan_rev_range_opt_changed_cb( GtkComboBox *combo, gpointer user_data );
349 static void loan_rev_range_changed_cb( GNCDateEdit *gde, gpointer user_data );
350 static void loan_rev_get_loan_range( LoanAssistantData *ldd, GDate *start, GDate *end );
351 static void loan_rev_get_dates( LoanAssistantData *ldd, GDate *start, GDate *end );
352 static void loan_rev_update_view( LoanAssistantData *ldd, GDate *start, GDate *end );
353 static void loan_rev_sched_list_free( gpointer data, gpointer user_data );
354 static void loan_rev_hash_to_list( gpointer key, gpointer val, gpointer user_data );
355 static void loan_rev_hash_free_date_keys( gpointer key, gpointer val, gpointer user_data );
356 
357 static void loan_get_pmt_formula( LoanAssistantData *ldd, GString *gstr );
358 static void loan_get_ppmt_formula( LoanAssistantData *ldd, GString *gstr );
359 static void loan_get_ipmt_formula( LoanAssistantData *ldd, GString *gstr );
360 static float loan_apr_to_simple_formula (float rate, float compounding_periods);
361 
362 static void loan_create_sxes( LoanAssistantData *ldd );
363 static gint loan_find_ttsplit_with_acct( gconstpointer elt, gconstpointer crit );
364 static void loan_create_sx_from_tcSX( LoanAssistantData *ldd, toCreateSX *tcSX );
365 static void loan_tcSX_free( gpointer data, gpointer user_data );
366 
367 void loan_assistant_prepare( GtkAssistant *assistant, GtkWidget *page, gpointer user_data );
368 void loan_assistant_finish( GtkAssistant *gtkassistant, gpointer user_data );
369 void loan_assistant_cancel( GtkAssistant *gtkassistant, gpointer user_data );
370 void loan_assistant_close( GtkAssistant *gtkassistant, gpointer user_data );
371 
372 /*****************************************************************************/
373 
374 
375 static
376 void
377 loan_assistant_close_handler( gpointer user_data )
378 {
379  LoanAssistantData *ldd = user_data;
380  gtk_widget_destroy( ldd->window );
381 }
382 
383 
384 static
385 void
386 loan_assistant_window_destroy_cb( GtkObject *object, gpointer user_data )
387 {
388  LoanAssistantData *ldd = user_data;
389 
390  g_assert( ldd );
391 
392  gnc_unregister_gui_component_by_data (DIALOG_LOAN_ASSISTANT_CM_CLASS, ldd);
393 
394  /* free alloc'd mem; cleanup */
395 
396  /* repay opts */
397  {
398  int i;
399 
400  g_date_free( ldd->ld.startDate );
401  g_date_free( ldd->ld.varStartDate );
402  recurrenceListFree(&ldd->ld.loan_schedule);
403 
404  if ( ldd->ld.repMemo )
405  g_free( ldd->ld.repMemo );
406 
407  for ( i = 0; i < ldd->ld.repayOptCount; i++ )
408  {
409  RepayOptData *rod = ldd->ld.repayOpts[i];
410  if ( rod->name )
411  g_free( rod->name );
412  if ( rod->txnMemo )
413  g_free( rod->txnMemo );
414 
415  if ( rod->startDate )
416  g_date_free( rod->startDate );
417 
418  if (rod->schedule != NULL)
419  recurrenceListFree(&rod->schedule);
420 
421  g_free( ldd->ld.repayOpts[i] );
422  g_free( ldd->repayOptsUI[i] );
423  }
424  g_free( ldd->ld.repayOpts );
425  g_free( ldd->repayOptsUI );
426 
427  if ( ldd->ld.repAmount )
428  g_free( ldd->ld.repAmount );
429 
430  g_date_free( ldd->ld.repStartDate );
431  }
432 
433  /* review */
434  {
435  if ( ldd->ld.revSchedule )
436  {
437  g_list_foreach( ldd->ld.revSchedule,
438  loan_rev_sched_list_free,
439  NULL );
440  g_list_free( ldd->ld.revSchedule );
441  ldd->ld.revSchedule = NULL;
442  }
443  }
444 
445  g_free( ldd );
446 }
447 
448 
449 static GtkWidget *
450 gnc_loan_assistant_create( LoanAssistantData *ldd )
451 {
452  GtkBuilder *builder;
453  GtkWidget *window;
454 
455  loan_assistant_data_init( ldd );
456 
457  builder = gtk_builder_new();
458 
459  gnc_builder_add_from_file (builder , "assistant-loan.glade", "len_liststore");
460  gnc_builder_add_from_file (builder , "assistant-loan.glade", "range_liststore");
461  gnc_builder_add_from_file (builder , "assistant-loan.glade", "type_liststore");
462  gnc_builder_add_from_file (builder , "assistant-loan.glade", "rate_liststore");
463 
464  gnc_builder_add_from_file (builder , "assistant-loan.glade", "Loan-Mortgage Assistant");
465  window = GTK_WIDGET(gtk_builder_get_object (builder, "Loan-Mortgage Assistant"));
466  ldd->window = window;
467 
468 
469  /* Set the assistant colors */
470  gnc_assistant_set_colors (GTK_ASSISTANT (ldd->window));
471 
472  /* Enable buttons on complete pages. */
473  gtk_assistant_set_page_complete (GTK_ASSISTANT (window),
474  GTK_WIDGET(gtk_builder_get_object(builder, "loan_intro_page")),
475  TRUE);
476  gtk_assistant_set_page_complete (GTK_ASSISTANT (window),
477  GTK_WIDGET(gtk_builder_get_object(builder, "loan_options_page")),
478  TRUE);
479  gtk_assistant_set_page_complete (GTK_ASSISTANT (window),
480  GTK_WIDGET(gtk_builder_get_object(builder, "loan_review_page")),
481  TRUE);
482 
483  /* Information Page */
484  {
485  ldd->prmTable = GTK_TABLE(gtk_builder_get_object(builder, "param_table"));
486  ldd->prmVarFrame = GTK_FRAME(gtk_builder_get_object(builder, "type_freq_frame"));
487  ldd->prmIrateSpin = GTK_SPIN_BUTTON (gtk_builder_get_object(builder, "irate_spin"));
488  ldd->prmType = GTK_COMBO_BOX (gtk_builder_get_object(builder, "type_combobox"));
489  gtk_combo_box_set_active( GTK_COMBO_BOX( ldd->prmType), 0 );
490  ldd->prmLengthSpin = GTK_SPIN_BUTTON (gtk_builder_get_object(builder, "len_spin"));
491  ldd->prmLengthType = GTK_COMBO_BOX (gtk_builder_get_object(builder, "len_opt"));
492  gtk_combo_box_set_active( GTK_COMBO_BOX( ldd->prmLengthType), 0 );
493  ldd->prmRemainSpin = GTK_SPIN_BUTTON (gtk_builder_get_object(builder, "rem_spin"));
494  ldd->prmIrateType = GTK_COMBO_BOX (gtk_builder_get_object(builder, "irate_type_combobox"));
495  gtk_combo_box_set_active( GTK_COMBO_BOX( ldd->prmIrateType), 0 );
496  /* ldd->prmStartDateGDE */
497  }
498  /* Repayment Page */
499  {
500  ldd->repTable = GTK_TABLE(gtk_builder_get_object(builder, "repay_table"));
501  ldd->repTxnName = GTK_ENTRY(gtk_builder_get_object(builder, "txn_title"));
502  ldd->repAmtEntry = GTK_ENTRY(gtk_builder_get_object(builder, "amount_ent"));
503  ldd->repFreqFrame = GTK_FRAME(gtk_builder_get_object(builder, "freq_frame"));
504  }
505  /* Options Page */
506  {
507  ldd->optVBox = GTK_VBOX(gtk_builder_get_object(builder, "loan_options_page"));
508  ldd->optEscrowCb = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "opt_escrow_cb"));
509  ldd->optEscrowHBox = GTK_HBOX(gtk_builder_get_object(builder, "opt_escrow_hbox"));
510  }
511  /* Payment Page */
512  {
513  ldd->payTable = GTK_TABLE(gtk_builder_get_object(builder, "pay_table"));
514  ldd->payTxnName = GTK_ENTRY(gtk_builder_get_object(builder, "pay_txn_title"));
515  ldd->payAmtEntry = GTK_ENTRY(gtk_builder_get_object(builder, "pay_amt_ent"));
516  ldd->payUseEscrow = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "pay_use_escrow"));
517  ldd->paySpecSrcAcct = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "pay_specify_source"));
518  ldd->payAcctFromLabel = GTK_LABEL(gtk_builder_get_object(builder, "pay_from_account_label"));
519  ldd->payEscToLabel = GTK_LABEL(gtk_builder_get_object(builder, "pay_escrow_to_label"));
520  ldd->payEscFromLabel = GTK_LABEL(gtk_builder_get_object(builder, "pay_escrow_from_label"));
521  ldd->payTxnFreqPartRb = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "pay_txn_part_rb"));
522  ldd->payTxnFreqUniqRb = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "pay_uniq_freq_rb"));
523  ldd->payFreqAlign = GTK_ALIGNMENT(gtk_builder_get_object(builder, "pay_freq_align"));
524  }
525  /* Review Page */
526  {
527  ldd->revTable = GTK_TABLE(gtk_builder_get_object(builder, "rev_date_range_table"));
528  ldd->revRangeOpt = GTK_COMBO_BOX(gtk_builder_get_object(builder, "rev_range_opt"));
529  ldd->revDateFrame = GTK_FRAME(gtk_builder_get_object(builder, "rev_date_frame"));
530  ldd->revScrollWin = GTK_SCROLLED_WINDOW(gtk_builder_get_object(builder, "rev_scrollwin"));
531  /* GNCDateEdit *revStartDate */
532  /* GNCDateEdit *revEndDate */
533  }
534 
535  /* non-buildable widget setup */
536  {
537  GtkWidget *butt;
538  int i;
539  // ACCT_TYPE_LIABILITY
540  GList *liabilityAcct;
541  // ACCT_TYPE_BANK, ACCT_TYPE_CASH, ACCT_TYPE_CREDIT,
542  // ACCT_TYPE_ASSET + ACCT_TYPE_LIABILITY
543  GList *paymentFromAccts;
544  // ACCT_TYPE_EXPENSE, ACCT_TYPE_LIABILITY, + payment-froms.
545  GList *paymentToAccts;
546  int fromLen = 5;
547  GNCAccountType paymentFroms[] = { ACCT_TYPE_BANK, ACCT_TYPE_CASH,
550  };
551  int toLen = 1;
552  GNCAccountType paymentTos[] = { ACCT_TYPE_EXPENSE };
553 
554  liabilityAcct = NULL;
555  paymentFromAccts = NULL;
556  paymentToAccts = NULL;
557 
558  liabilityAcct = g_list_append( liabilityAcct,
559  GINT_TO_POINTER( ACCT_TYPE_LIABILITY ) );
560  for ( i = 0; i < fromLen; i++ )
561  {
562  paymentFromAccts
563  = g_list_append( paymentFromAccts,
564  GINT_TO_POINTER( paymentFroms[i] ) );
565  paymentToAccts
566  = g_list_append( paymentToAccts,
567  GINT_TO_POINTER( paymentFroms[i] ) );
568  }
569 
570  for ( i = 0; i < toLen; i++ )
571  {
572  paymentToAccts = g_list_append( paymentToAccts,
573  GINT_TO_POINTER( paymentTos[i] ) );
574  }
575 
576  /* All of the GncAccountSel[ectors]... */
577  {
578  int i;
579  GtkAlignment *a;
580  /* "gas" == GncAccountSel */
581  struct gas_in_tables_data
582  {
583  GNCAccountSel **loc;
584  GtkTable *table;
585  gboolean newAcctAbility;
586  int left, right, top, bottom;
587  GList *allowableAccounts;
588  } gas_data[] =
589  {
590  /* These ints are the GtkTable boundries */
591  { &ldd->prmAccountGAS, ldd->prmTable, TRUE, 1, 4, 0, 1, liabilityAcct },
592  { &ldd->repAssetsFromGAS, ldd->repTable, TRUE, 1, 4, 2, 3, paymentFromAccts },
593  { &ldd->repPrincToGAS, ldd->repTable, TRUE, 1, 2, 3, 4, paymentToAccts },
594  { &ldd->repIntToGAS, ldd->repTable, TRUE, 3, 4, 3, 4, paymentToAccts },
595  { &ldd->payAcctFromGAS, ldd->payTable, TRUE, 1, 2, 4, 5, paymentFromAccts },
596  { &ldd->payAcctEscToGAS, ldd->payTable, FALSE, 3, 4, 4, 5, paymentToAccts },
597  { &ldd->payAcctEscFromGAS, ldd->payTable, FALSE, 1, 2, 5, 6, paymentFromAccts },
598  { &ldd->payAcctToGAS, ldd->payTable, TRUE, 3, 4, 5, 6, paymentToAccts },
599  { NULL }
600  };
601 
602  /* left-aligned, 25%-width */
603  a = GTK_ALIGNMENT(gtk_alignment_new( 0.0, 0.5, 0.25, 1.0 ));
604  ldd->prmOrigPrincGAE = GNC_AMOUNT_EDIT(gnc_amount_edit_new());
605  gtk_container_add( GTK_CONTAINER(a), GTK_WIDGET(ldd->prmOrigPrincGAE) );
606  gtk_table_attach( ldd->prmTable, GTK_WIDGET(a),
607  1, 4, 1, 2,
608  GTK_EXPAND | GTK_FILL,
609  GTK_EXPAND | GTK_FILL, 2, 2 );
610 
611  for ( i = 0; gas_data[i].loc != NULL; i++ )
612  {
613  GNCAccountSel *gas;
614 
615  a = GTK_ALIGNMENT(gtk_alignment_new( 0.0, 0.5, 0.25, 1.0 ));
616  gas = GNC_ACCOUNT_SEL(gnc_account_sel_new());
617  gnc_account_sel_set_new_account_ability(
618  gas, gas_data[i].newAcctAbility );
619  if ( gas_data[i].allowableAccounts != NULL )
620  {
621  gnc_account_sel_set_acct_filters(
622  gas, gas_data[i].allowableAccounts, NULL );
623  }
624  gtk_container_add( GTK_CONTAINER(a),
625  GTK_WIDGET(gas) );
626  gtk_table_attach( gas_data[i].table,
627  GTK_WIDGET(a),
628  gas_data[i].left,
629  gas_data[i].right,
630  gas_data[i].top,
631  gas_data[i].bottom,
632  GTK_EXPAND | GTK_FILL,
633  GTK_EXPAND | GTK_FILL, 2, 2 );
634  *(gas_data[i].loc) = gas;
635  }
636  }
637 
638  /* Setup the payment page always-insensitive GASes */
639  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payAcctEscToGAS), FALSE );
640  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payAcctEscFromGAS), FALSE );
641 
642  /* The GNCDateEdit[s] */
643  {
644  /* "gde" == GNCDateEdit */
645  struct gde_in_tables_data
646  {
647  GNCDateEdit **loc;
648  GtkTable *table;
649  int left, right, top, bottom;
650  } gde_data[] =
651  {
652  /* These ints are the GtkTable boundries */
653  { &ldd->prmStartDateGDE, ldd->prmTable, 1, 2, 4, 5 },
654  { &ldd->revStartDate, ldd->revTable, 1, 2, 0, 1 },
655  { &ldd->revEndDate, ldd->revTable, 1, 2, 1, 2 },
656  { NULL }
657  };
658 
659  for ( i = 0; gde_data[i].loc != NULL; i++ )
660  {
661  *gde_data[i].loc =
662  GNC_DATE_EDIT(
663  gnc_date_edit_new( gnc_time (NULL),
664  FALSE, FALSE ) );
665  gtk_table_attach( gde_data[i].table,
666  GTK_WIDGET( *gde_data[i].loc ),
667  gde_data[i].left,
668  gde_data[i].right,
669  gde_data[i].top,
670  gde_data[i].bottom,
671  (GTK_EXPAND | GTK_FILL),
672  GTK_FILL, 0, 0 );
673  }
674 
675  }
676 
677  gtk_widget_set_sensitive( GTK_WIDGET(ldd->prmVarFrame), FALSE );
678  {
679  g_signal_connect( ldd->prmType, "changed",
680  G_CALLBACK( loan_info_prm_type_cb ),
681  ldd );
682  }
683 
684  {
685  GtkAdjustment *a;
686 
687  /* 8.0 [%], range of 0.005..100.0 with ticks at 0.001[%]. */
688  a = GTK_ADJUSTMENT(gtk_adjustment_new( 8.0, 0.001,
689  100.0, 0.001,
690  1.0, 0.0 ));
691  gtk_spin_button_set_adjustment( ldd->prmIrateSpin, a );
692  gtk_spin_button_set_value( ldd->prmIrateSpin, 8.00 );
693  gtk_spin_button_set_snap_to_ticks( ldd->prmIrateSpin, TRUE );
694 
695  a = GTK_ADJUSTMENT(gtk_adjustment_new( 360, 1,
696  9999, 1,
697  12, 0.0 ));
698  gtk_spin_button_set_adjustment( ldd->prmLengthSpin, a );
699  g_signal_connect( ldd->prmLengthSpin, "changed",
700  G_CALLBACK( loan_info_calc_update_cb ),
701  ldd );
702  g_signal_connect( ldd->prmStartDateGDE, "date-changed",
703  G_CALLBACK( loan_info_calc_update_cb ),
704  ldd );
705  g_signal_connect( ldd->prmLengthSpin, "value-changed",
706  G_CALLBACK( loan_info_calc_update_cb ),
707  ldd );
708  g_signal_connect( ldd->prmLengthType, "changed",
709  G_CALLBACK( loan_info_calc_update_cb ),
710  ldd );
711 
712  a = GTK_ADJUSTMENT(gtk_adjustment_new( 360, 1,
713  9999, 1,
714  12, 0.0 ));
715  gtk_spin_button_set_adjustment( ldd->prmRemainSpin, a );
716  }
717 
718  g_signal_connect( ldd->optEscrowCb, "toggled",
719  G_CALLBACK(loan_opt_escrow_toggle_cb), ldd );
720  gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), FALSE );
721  ldd->optEscrowGAS = GNC_ACCOUNT_SEL(gnc_account_sel_new());
722  gnc_account_sel_set_new_account_ability( ldd->optEscrowGAS, TRUE );
723  gtk_container_add( GTK_CONTAINER(ldd->optEscrowHBox),
724  GTK_WIDGET(ldd->optEscrowGAS) );
725 
726  {
727  /* . Each RepayOpt gets an "entry" in the optContainer.
728  * . Each "entry" is a 2-line vbox containing:
729  * . The checkbox for the option itself
730  * . an alignment-contained sub-checkbox for "through the
731  * escrow account".
732  * . Hook up each to bit-twiddling the appropriate line.
733  */
734 
735  RepayOptUIData *rouid;
736  GtkVBox *vb;
737  GtkAlignment *optAlign, *subOptAlign;
738  GString *str;
739 
740  str = g_string_sized_new( 32 );
741 
742  for ( i = 0; i < ldd->ld.repayOptCount; i++ )
743  {
744  rouid = ldd->repayOptsUI[i];
745  vb = GTK_VBOX(gtk_vbox_new( FALSE, 2 ));
746 
747  /* Add payment checkbox. */
748 
749  /* Translators: %s is "Taxes",
750  * "Insurance", or similar. */
751  g_string_printf( str, _("... pay \"%s\"?"),
752  rouid->optData->name );
753  rouid->optCb =
754  GTK_CHECK_BUTTON(
755  gtk_check_button_new_with_label(
756  str->str ));
757  gtk_box_pack_start( GTK_BOX(vb),
758  GTK_WIDGET(rouid->optCb),
759  FALSE, FALSE, 2 );
760  rouid->escrowCb =
761  GTK_CHECK_BUTTON(
762  gtk_check_button_new_with_label(
763  _("via Escrow account?") ));
764  gtk_widget_set_sensitive(
765  GTK_WIDGET(rouid->escrowCb),
766  FALSE );
767  subOptAlign =
768  GTK_ALIGNMENT(
769  gtk_alignment_new(
770  0.5, 0.5, 0.75, 1.0 ));
771  gtk_container_add( GTK_CONTAINER(subOptAlign),
772  GTK_WIDGET(rouid->escrowCb) );
773  gtk_box_pack_start( GTK_BOX(vb), GTK_WIDGET(subOptAlign),
774  FALSE, FALSE, 2 );
775 
776  g_signal_connect( rouid->optCb, "toggled",
777  G_CALLBACK(loan_opt_toggled_cb),
778  rouid );
779  g_signal_connect( rouid->optCb, "toggled",
780  G_CALLBACK(loan_opt_consistency_cb),
781  rouid );
782  g_signal_connect( rouid->escrowCb, "toggled",
783  G_CALLBACK(loan_opt_escrow_toggled_cb),
784  rouid );
785 
786  optAlign = GTK_ALIGNMENT(gtk_alignment_new( 0.5, 0.5, 0.75, 1.0 ));
787  gtk_container_add( GTK_CONTAINER(optAlign),
788  GTK_WIDGET(vb) );
789  gtk_box_pack_start( GTK_BOX(ldd->optVBox), GTK_WIDGET(optAlign),
790  FALSE, FALSE, 2 );
791  gtk_widget_show_all( GTK_WIDGET(optAlign) );
792  }
793  g_string_free( str, TRUE );
794  }
795 
796  g_signal_connect( ldd->payUseEscrow, "toggled",
797  G_CALLBACK(loan_pay_use_esc_toggle_cb), ldd );
798  g_signal_connect( ldd->paySpecSrcAcct, "toggled",
799  G_CALLBACK(loan_pay_spec_src_toggle_cb), ldd );
800  g_signal_connect( ldd->payTxnFreqUniqRb, "toggled",
801  G_CALLBACK(loan_pay_freq_toggle_cb), ldd );
802 
803  {
804  GtkHBox *hbox;
805  hbox = GTK_HBOX(gtk_builder_get_object(builder, "type_freq_hbox"));
806  ldd->prmVarGncFreq = GNC_FREQUENCY(gnc_frequency_new( NULL, NULL ));
807  gtk_box_pack_start( GTK_BOX(hbox) , GTK_WIDGET(ldd->prmVarGncFreq), TRUE, FALSE, 0 );
808  g_signal_connect (ldd->prmVarGncFreq, "changed",
809  G_CALLBACK (loan_info_page_valid_cb), ldd);
810  }
811  {
812  GtkHBox *hbox;
813  hbox = GTK_HBOX(gtk_builder_get_object(builder, "freq_frame_hbox"));
814  ldd->repGncFreq = GNC_FREQUENCY(gnc_frequency_new( NULL, NULL ));
815  gtk_box_pack_start( GTK_BOX(hbox) , GTK_WIDGET(ldd->repGncFreq), TRUE, FALSE, 0 );
816  g_signal_connect (ldd->repGncFreq, "changed",
817  G_CALLBACK (loan_rep_page_valid_cb), ldd);
818  }
819 
820  ldd->payGncFreq = GNC_FREQUENCY(gnc_frequency_new( NULL, NULL ));
821  gtk_container_add( GTK_CONTAINER(ldd->payFreqAlign), GTK_WIDGET(ldd->payGncFreq) );
822  g_signal_connect (ldd->payGncFreq, "changed",
823  G_CALLBACK (loan_pay_page_valid_cb), ldd);
824 
825  butt = GTK_WIDGET(gtk_builder_get_object(builder, "pay_back_button"));
826  g_signal_connect (butt, "clicked",
827  G_CALLBACK (loan_pay_back_button_cb), ldd);
828 
829  butt = GTK_WIDGET(gtk_builder_get_object(builder, "pay_next_button"));
830  g_signal_connect (butt, "clicked",
831  G_CALLBACK (loan_pay_next_button_cb), ldd);
832 
833  }
834 
835  /* Info page Call Back */
836  {
837  g_signal_connect (ldd->prmAccountGAS, "account_sel_changed",
838  G_CALLBACK (loan_info_page_valid_cb), ldd);
839  g_signal_connect( ldd->prmIrateType, "changed",
840  G_CALLBACK( loan_info_page_valid_cb ), ldd );
841  }
842  /* Opts page Call Back */
843  {
844  g_signal_connect (ldd->optEscrowGAS, "account_sel_changed",
845  G_CALLBACK (loan_opt_page_valid_cb), ldd);
846  }
847  /* Rep page Call Back */
848  {
849  g_signal_connect (ldd->repAssetsFromGAS, "account_sel_changed",
850  G_CALLBACK (loan_rep_page_valid_cb), ldd);
851  g_signal_connect (ldd->repIntToGAS, "account_sel_changed",
852  G_CALLBACK (loan_rep_page_valid_cb), ldd);
853  g_signal_connect (ldd->repPrincToGAS, "account_sel_changed",
854  G_CALLBACK (loan_rep_page_valid_cb), ldd);
855  }
856  /* Pay page Call Back */
857  {
858  g_signal_connect (ldd->payAcctFromGAS, "account_sel_changed",
859  G_CALLBACK (loan_pay_page_valid_cb), ldd);
860  g_signal_connect (ldd->payAcctToGAS, "account_sel_changed",
861  G_CALLBACK (loan_pay_page_valid_cb), ldd);
862  g_signal_connect (ldd->payAcctEscFromGAS, "account_sel_changed",
863  G_CALLBACK (loan_pay_page_valid_cb), ldd);
864  g_signal_connect (ldd->payAcctEscToGAS, "account_sel_changed",
865  G_CALLBACK (loan_pay_page_valid_cb), ldd);
866  }
867  /* Review page Call Back */
868  {
869  gtk_combo_box_set_active( ldd->revRangeOpt, 0 );
870  g_signal_connect( ldd->revRangeOpt, "changed",
871  G_CALLBACK( loan_rev_range_opt_changed_cb ),
872  ldd );
873  g_signal_connect( ldd->revStartDate, "date-changed",
874  G_CALLBACK( loan_rev_range_changed_cb ),
875  ldd );
876  g_signal_connect( ldd->revEndDate, "date-changed",
877  G_CALLBACK( loan_rev_range_changed_cb ),
878  ldd );
879  }
880 
881  g_signal_connect( ldd->window, "destroy",
882  G_CALLBACK(loan_assistant_window_destroy_cb),
883  ldd );
884 
885  gtk_builder_connect_signals(builder, ldd);
886  g_object_unref(G_OBJECT(builder));
887 
888  gtk_widget_show_all( ldd->window );
889  return window;
890 }
891 
892 
893 static
894 void
895 loan_assistant_data_init( LoanAssistantData *ldd )
896 {
897  int i, optCount;
898  RepayOptData *optData;
899 
900  /* get the count of repayment defaults. */
901  for ( optCount = 0; REPAY_DEFAULTS[optCount].name != NULL; optCount++ )
902  ;
903 
904  ldd->currentIdx = -1;
905 
906  ldd->ld.principal = gnc_numeric_zero();
907  ldd->ld.startDate = g_date_new();
908  ldd->ld.varStartDate = g_date_new();
909  gnc_gdate_set_time64( ldd->ld.startDate, gnc_time (NULL) );
910  ldd->ld.loan_schedule = NULL;
911  ldd->ld.repayment_schedule = NULL;
912  {
913  Recurrence *r = g_new0(Recurrence, 1);
914  recurrenceSet(r, 1, PERIOD_MONTH, ldd->ld.startDate, WEEKEND_ADJ_NONE);
915  ldd->ld.repayment_schedule = g_list_append(ldd->ld.repayment_schedule, r);
916  }
917 
918  ldd->ld.repMemo = g_strdup( _("Loan") );
919  ldd->ld.repAmount = NULL;
920  ldd->ld.repStartDate = g_date_new();
921  ldd->ld.repayOptCount = optCount;
922  ldd->ld.repayOpts = g_new0( RepayOptData*, optCount );
923  /* copy all the default lines into the LDD */
924  ldd->repayOptsUI = g_new0( RepayOptUIData*, optCount );
925  for ( i = 0; i < optCount; i++ )
926  {
927  g_assert( REPAY_DEFAULTS[i].name != NULL );
928 
929  ldd->repayOptsUI[i] = g_new0( RepayOptUIData, 1 );
930  ldd->repayOptsUI[i]->ldd = ldd;
931 
932  optData = ldd->ld.repayOpts[i]
933  = ldd->repayOptsUI[i]->optData
934  = g_new0( RepayOptData, 1 );
935 
936  optData->enabled = FALSE;
937  optData->optValid = FALSE;
938  optData->FreqUniq = FALSE;
939  optData->name = g_strdup( _(REPAY_DEFAULTS[i].name) );
940  optData->txnMemo = g_strdup( _(REPAY_DEFAULTS[i].
941  defaultTxnMemo) );
942  optData->amount = 0.0;
943  optData->throughEscrowP = REPAY_DEFAULTS[i].escrowDefault;
944  optData->specSrcAcctP = REPAY_DEFAULTS[i].specSrcAcctDefault;
945  optData->schedule = NULL;
946  optData->startDate = NULL;
947  }
948 }
949 
950 /************************ Page functions in order ***********************/
951 
952 static
953 void
954 loan_info_prep( GtkAssistant *assistant, gpointer user_data )
955 {
956  LoanAssistantData *ldd = user_data;
957 
958  gnc_amount_edit_set_amount( ldd->prmOrigPrincGAE, ldd->ld.principal );
959  gtk_spin_button_set_value( ldd->prmIrateSpin, ldd->ld.interestRate );
960  gtk_combo_box_set_active( ldd->prmIrateType, ldd->ld.rateType );
961  gtk_combo_box_set_active( ldd->prmType, ldd->ld.type );
962  if ( ldd->ld.type != GNC_FIXED )
963  {
964  g_signal_handlers_block_by_func( GNC_FREQUENCY( ldd->prmVarGncFreq), loan_info_page_valid_cb , ldd );
965  gnc_frequency_setup_recurrence(ldd->prmVarGncFreq, ldd->ld.loan_schedule, ldd->ld.varStartDate);
966  g_signal_handlers_unblock_by_func( GNC_FREQUENCY( ldd->prmVarGncFreq), loan_info_page_valid_cb , ldd );
967  }
968 
969  /* start date */
970  {
971  struct tm *tmpTm;
972 
973  tmpTm = g_new0( struct tm, 1 );
974 
975  g_date_to_struct_tm (ldd->ld.startDate, tmpTm);
976  gnc_date_edit_set_time (ldd->prmStartDateGDE,
977  gnc_mktime (tmpTm));
978  g_free (tmpTm);
979  }
980 
981  /* length: total and remaining */
982  {
983  gtk_spin_button_set_value( ldd->prmLengthSpin, ldd->ld.numPer );
984  gtk_combo_box_set_active( ldd->prmLengthType, ldd->ld.perSize );
985  gtk_spin_button_set_value( ldd->prmRemainSpin, ldd->ld.numMonRemain );
986  }
987 }
988 
989 
990 static
991 void
992 loan_info_prm_type_cb( GtkWidget *w, gpointer user_data )
993 {
994  LoanAssistantData *ldd = user_data;
995  gint index;
996 
997  index = gtk_combo_box_get_active( ldd->prmType );
998  gtk_widget_set_sensitive( GTK_WIDGET(ldd->prmVarFrame),
999  index != GNC_FIXED );
1000 }
1001 
1002 
1003 static
1004 void
1005 loan_info_calc_update_cb( GtkWidget *w, gpointer user_data )
1006 {
1007  LoanAssistantData *ldd = user_data;
1008  GDate start, now;
1009  int i, totalVal, total, remain;
1010 
1011  g_date_clear( &start, 1 );
1012  g_date_clear( &now, 1 );
1013  gnc_gdate_set_time64( &start, gnc_date_edit_get_date( ldd->prmStartDateGDE ) );
1014  gnc_gdate_set_time64( &now, gnc_time (NULL) );
1015  for ( i = 0; g_date_compare( &start, &now ) < 0; i++ )
1016  {
1017  g_date_add_months( &start, 1 );
1018  }
1019 
1020  /* Get the correct, current value of the length spin. */
1021  {
1022  gchar *valueStr = gtk_editable_get_chars( GTK_EDITABLE(ldd->prmLengthSpin),
1023  0, -1 );
1024  totalVal = strtol( valueStr, NULL, 10 );
1025  g_free( valueStr );
1026  }
1027  total = totalVal
1028  * ( gtk_combo_box_get_active( ldd->prmLengthType )
1029  == 1 ? 12 : 1 );
1030  remain = total - i;
1031  gtk_spin_button_set_value( ldd->prmRemainSpin, remain );
1032  gtk_widget_show( GTK_WIDGET(ldd->prmRemainSpin) );
1033 }
1034 
1035 
1036 void
1037 loan_info_page_valid_cb (GtkWidget *widget, gpointer user_data )
1038 {
1039  LoanAssistantData *ldd = user_data;
1040  GtkAssistant *assistant = GTK_ASSISTANT(ldd->window);
1041  gint num = gtk_assistant_get_current_page (assistant);
1042  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
1043 
1044  gtk_assistant_set_page_complete (assistant, page,
1045  loan_info_page_complete (assistant, ldd));
1046 }
1047 
1048 
1049 static
1050 gboolean
1051 loan_info_page_complete( GtkAssistant *assistant, gpointer user_data )
1052 {
1053  LoanAssistantData *ldd = user_data;
1054 
1055  ldd->ld.primaryAcct = gnc_account_sel_get_account( ldd->prmAccountGAS );
1056  /* Test for valid Account */
1057  if ( ldd->ld.primaryAcct == NULL )
1058  return FALSE;
1059 
1060  return TRUE;
1061 }
1062 
1063 
1064 static
1065 void
1066 loan_info_page_save( GtkAssistant *assistant, gpointer user_data )
1067 {
1068  LoanAssistantData *ldd = user_data;
1069 
1070  ldd->ld.primaryAcct = gnc_account_sel_get_account( ldd->prmAccountGAS );
1071 
1072  if ( ! ldd->ld.repPriAcct )
1073  {
1074  ldd->ld.repPriAcct = ldd->ld.primaryAcct;
1075  }
1076  ldd->ld.principal = gnc_amount_edit_get_amount( ldd->prmOrigPrincGAE );
1077  ldd->ld.interestRate = gtk_spin_button_get_value( ldd->prmIrateSpin );
1078  ldd->ld.rateType = gtk_combo_box_get_active (ldd->prmIrateType );
1079  ldd->ld.type = gtk_combo_box_get_active( ldd->prmType );
1080 
1081  if ( ldd->ld.type != GNC_FIXED )
1082  {
1083  recurrenceListFree(&ldd->ld.loan_schedule);
1084  gnc_frequency_save_to_recurrence(ldd->prmVarGncFreq,
1085  &ldd->ld.loan_schedule,
1086  ldd->ld.varStartDate);
1087  }
1088 
1089  /* start date */
1090  {
1091  time64 tmpTT;
1092  struct tm *tmpTm;
1093 
1094  tmpTT = gnc_date_edit_get_date( ldd->prmStartDateGDE );
1095  tmpTm = gnc_localtime ( &tmpTT );
1096  g_date_set_dmy( ldd->ld.startDate,
1097  tmpTm->tm_mday,
1098  (tmpTm->tm_mon + 1),
1099  (1900 + tmpTm->tm_year) );
1100  gnc_tm_free (tmpTm);
1101  }
1102 
1103  /* len / periods */
1104  {
1105  ldd->ld.perSize =
1106  (gtk_combo_box_get_active( ldd->prmLengthType )
1107  == GNC_MONTHS) ? GNC_MONTHS : GNC_YEARS;
1108  ldd->ld.numPer =
1109  gtk_spin_button_get_value_as_int( ldd->prmLengthSpin );
1110  ldd->ld.numMonRemain =
1111  gtk_spin_button_get_value_as_int( ldd->prmRemainSpin );
1112  }
1113 }
1114 
1115 /************************************************************************/
1116 
1117 static
1118 void
1119 loan_opt_prep( GtkAssistant *assistant, gpointer user_data )
1120 {
1121  int i;
1122  RepayOptUIData *rouid;
1123  LoanAssistantData *ldd = user_data;
1124 
1125  /* Save Previous Page ( Information ) */
1126  loan_info_page_save(assistant, ldd);
1127 
1128  if ( ldd->ld.escrowAcct )
1129  {
1130  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb), TRUE );
1131  gnc_account_sel_set_account( ldd->optEscrowGAS, ldd->ld.escrowAcct, FALSE );
1132  }
1133  for ( i = 0; i < ldd->ld.repayOptCount; i++ )
1134  {
1135  rouid = ldd->repayOptsUI[i];
1136  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(rouid->optCb),
1137  rouid->optData->enabled );
1138  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(rouid->escrowCb),
1139  rouid->optData->throughEscrowP
1140  && rouid->optData->enabled
1141  && ldd->ld.escrowAcct );
1142  gtk_widget_set_sensitive( GTK_WIDGET(rouid->escrowCb),
1143  rouid->optData->enabled
1144  && ldd->ld.escrowAcct );
1145  }
1146 }
1147 
1148 
1149 static
1150 void
1151 loan_opt_toggled_cb( GtkToggleButton *tb, gpointer user_data )
1152 {
1153  RepayOptUIData *rouid;
1154 
1155  rouid = (RepayOptUIData*)user_data;
1156  rouid->optData->enabled = gtk_toggle_button_get_active(tb);
1157 }
1158 
1159 
1160 static
1161 void
1162 loan_opt_consistency_cb( GtkToggleButton *tb, gpointer user_data )
1163 {
1164  GtkToggleButton *escrowCb;
1165  RepayOptUIData *rouid;
1166 
1167  rouid = (RepayOptUIData*)user_data;
1168  escrowCb = GTK_TOGGLE_BUTTON(rouid->escrowCb);
1169  /* make sure the escrow option is only selected if we're active. */
1170  gtk_toggle_button_set_active( escrowCb,
1171  gtk_toggle_button_get_active(
1172  GTK_TOGGLE_BUTTON(
1173  rouid->ldd->optEscrowCb) )
1174  && rouid->optData->throughEscrowP
1175  && gtk_toggle_button_get_active(tb) );
1176  /* make sure the escrow option is only sensitive if we're active, and
1177  * the escrow account is enabled */
1178  gtk_widget_set_sensitive( GTK_WIDGET(escrowCb),
1179  gtk_toggle_button_get_active(tb)
1180  && gtk_toggle_button_get_active(
1181  GTK_TOGGLE_BUTTON(rouid->ldd->optEscrowCb)) );
1182 }
1183 
1184 
1185 static
1186 void
1187 loan_opt_escrow_toggle_cb( GtkToggleButton *tb, gpointer user_data )
1188 {
1189  int i;
1190  gboolean newState;
1191  RepayOptUIData *rouid;
1192  LoanAssistantData *ldd = user_data;
1193  GtkAssistant *assistant = GTK_ASSISTANT(ldd->window);
1194  gint num = gtk_assistant_get_current_page (assistant);
1195  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
1196 
1197  newState = gtk_toggle_button_get_active(tb);
1198  gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), newState );
1199  /* Check for Valid Account if enabled */
1200  if (newState)
1201  {
1202  if (GNC_ACCOUNT_SEL( ldd->ld.escrowAcct) == NULL)
1203  gtk_assistant_set_page_complete (assistant, page, FALSE);
1204  }
1205  else
1206  {
1207  ldd->ld.escrowAcct = NULL;
1208  gnc_account_sel_set_account( GNC_ACCOUNT_SEL( ldd->optEscrowGAS), NULL , FALSE );
1209  gtk_assistant_set_page_complete (assistant, page, TRUE);
1210  }
1211 
1212 
1213  /* deal with escrow options. */
1214  for ( i = 0; i < ldd->ld.repayOptCount; i++ )
1215  {
1216  rouid = ldd->repayOptsUI[i];
1217  /* If we're going off, then uncheck and desensitize all escrow opts. */
1218  /* If we're going on, then sensitize all escrow opts. */
1219 
1220  /* prevent the toggle handler from running and "trashing" the
1221  * state of the throughEscrowP selection */
1222  g_signal_handlers_block_by_func( rouid->escrowCb,
1223  loan_opt_escrow_toggled_cb,
1224  rouid );
1225  gtk_toggle_button_set_active(
1226  GTK_TOGGLE_BUTTON(rouid->escrowCb),
1227  ( newState
1228  && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rouid->optCb) )
1229  && rouid->optData->throughEscrowP ) );
1230  gtk_widget_set_sensitive(
1231  GTK_WIDGET(rouid->escrowCb),
1232  newState
1233  && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rouid->optCb) ) );
1234  g_signal_handlers_unblock_by_func( rouid->escrowCb,
1235  loan_opt_escrow_toggled_cb,
1236  rouid );
1237  if ( newState )
1238  {
1239  rouid->optData->from = ldd->ld.escrowAcct;
1240  }
1241  else
1242  {
1243  rouid->optData->from = NULL;
1244  }
1245  }
1246 }
1247 
1248 
1249 static
1250 void
1251 loan_opt_escrow_toggled_cb( GtkToggleButton *tb, gpointer user_data )
1252 {
1253  RepayOptUIData *rouid;
1254 
1255  rouid = (RepayOptUIData*)user_data;
1256  rouid->optData->throughEscrowP = gtk_toggle_button_get_active( tb );
1257 }
1258 
1259 
1260 void
1261 loan_opt_page_valid_cb (GtkWidget *widget, gpointer user_data )
1262 {
1263  LoanAssistantData *ldd = user_data;
1264 
1265  GtkAssistant *assistant = GTK_ASSISTANT(ldd->window);
1266  gint num = gtk_assistant_get_current_page (assistant);
1267  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
1268 
1269  gtk_assistant_set_page_complete (assistant, page,
1270  loan_opt_page_complete (assistant, ldd));
1271 }
1272 
1273 
1274 static
1275 gboolean
1276 loan_opt_page_complete( GtkAssistant *assistant, gpointer user_data )
1277 {
1278  LoanAssistantData *ldd = user_data;
1279 
1280  if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb) ) )
1281  {
1282  ldd->ld.escrowAcct =
1283  gnc_account_sel_get_account( ldd->optEscrowGAS );
1284  /* Test for valid Account */
1285  if ( ldd->ld.escrowAcct == NULL )
1286  return FALSE;
1287  }
1288  else
1289  {
1290  ldd->ld.escrowAcct = NULL;
1291  }
1292  return TRUE;
1293 }
1294 
1295 /************************************************************************/
1296 
1297 static
1298 void
1299 loan_rep_prep( GtkAssistant *assistant, gpointer user_data )
1300 {
1301  LoanAssistantData *ldd = user_data;
1302  GString *str;
1303 
1304  if ( ldd->ld.repAmount )
1305  {
1306  g_free( ldd->ld.repAmount );
1307  }
1308 
1309  str = g_string_sized_new( 64 );
1310  loan_get_pmt_formula( ldd, str);
1311  ldd->ld.repAmount = str->str;
1312  g_string_free( str, FALSE );
1313 
1314  if ( ldd->ld.repMemo )
1315  gtk_entry_set_text( ldd->repTxnName, ldd->ld.repMemo );
1316 
1317  if ( ldd->ld.repAmount )
1318  gtk_entry_set_text( ldd->repAmtEntry, ldd->ld.repAmount );
1319 
1320  gnc_account_sel_set_account( ldd->repAssetsFromGAS, ldd->ld.repFromAcct, FALSE );
1321  gnc_account_sel_set_account( ldd->repPrincToGAS, ldd->ld.repPriAcct, FALSE );
1322  gnc_account_sel_set_account( ldd->repIntToGAS, ldd->ld.repIntAcct, FALSE );
1323 
1324  g_signal_handlers_block_by_func( ldd->repGncFreq, loan_rep_page_valid_cb , ldd );
1325  gnc_frequency_setup_recurrence(ldd->repGncFreq, ldd->ld.repayment_schedule, ldd->ld.repStartDate);
1326  g_signal_handlers_unblock_by_func( ldd->repGncFreq, loan_rep_page_valid_cb , ldd );
1327 
1328  /* Find the first enabled option */
1329  {
1330  int i;
1331  for ( i = 0; // we can always start at 0, here.
1332  (i < ldd->ld.repayOptCount)
1333  && !ldd->ld.repayOpts[i]->enabled;
1334  i++ )
1335  ;
1336  if ( i < ldd->ld.repayOptCount )
1337  ldd->currentIdx = i;
1338  else
1339  ldd->currentIdx = -1;
1340  }
1341 }
1342 
1343 
1344 void
1345 loan_rep_page_valid_cb (GtkWidget *widget, gpointer user_data )
1346 {
1347  LoanAssistantData *ldd = user_data;
1348  GtkAssistant *assistant = GTK_ASSISTANT(ldd->window);
1349  gint num = gtk_assistant_get_current_page (assistant);
1350  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
1351 
1352  gtk_assistant_set_page_complete (assistant, page,
1353  loan_rep_page_complete (assistant, ldd));
1354 }
1355 
1356 
1357 static
1358 gboolean
1359 loan_rep_page_complete( GtkAssistant *assistant, gpointer user_data )
1360 {
1361  LoanAssistantData *ldd = user_data;
1362 
1363  ldd->ld.repFromAcct =
1364  gnc_account_sel_get_account( ldd->repAssetsFromGAS );
1365  /* Test for valid Account */
1366  if ( ldd->ld.repFromAcct == NULL )
1367  return FALSE;
1368 
1369  ldd->ld.repPriAcct =
1370  gnc_account_sel_get_account( ldd->repPrincToGAS );
1371  /* Test for valid Account */
1372  if ( ldd->ld.repPriAcct == NULL )
1373  return FALSE;
1374 
1375  ldd->ld.repIntAcct =
1376  gnc_account_sel_get_account( ldd->repIntToGAS );
1377  /* Test for valid Account */
1378  if ( ldd->ld.repIntAcct == NULL )
1379  return FALSE;
1380 
1381  return TRUE;
1382 }
1383 
1384 
1385 static
1386 void
1387 loan_rep_page_save( GtkAssistant *assistant, gpointer user_data )
1388 {
1389  LoanAssistantData *ldd = user_data;
1390 
1391  if ( ldd->ld.repMemo )
1392  g_free( ldd->ld.repMemo );
1393  ldd->ld.repMemo =
1394  gtk_editable_get_chars( GTK_EDITABLE(ldd->repTxnName), 0, -1 );
1395 
1396  if ( ldd->ld.repAmount )
1397  g_free( ldd->ld.repAmount );
1398  ldd->ld.repAmount =
1399  gtk_editable_get_chars( GTK_EDITABLE(ldd->repAmtEntry), 0, -1 );
1400 
1401  ldd->ld.repFromAcct =
1402  gnc_account_sel_get_account( ldd->repAssetsFromGAS );
1403 
1404  ldd->ld.repPriAcct =
1405  gnc_account_sel_get_account( ldd->repPrincToGAS );
1406 
1407  ldd->ld.repIntAcct =
1408  gnc_account_sel_get_account( ldd->repIntToGAS );
1409 
1410  recurrenceListFree(&ldd->ld.repayment_schedule);
1411  gnc_frequency_save_to_recurrence(ldd->repGncFreq,
1412  &ldd->ld.repayment_schedule,
1413  ldd->ld.repStartDate);
1414 }
1415 
1416 /************************************************************************/
1417 
1418 static
1419 void
1420 loan_pay_prep( GtkAssistant *assistant, gpointer user_data )
1421 {
1422  LoanAssistantData *ldd = user_data;
1423  RepayOptData *rod;
1424  GString *str;
1425 
1426 
1427  gint num = gtk_assistant_get_current_page (assistant);
1428  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
1429 
1430  /* Save Previous Page (Repayment) */
1431  loan_rep_page_save(assistant, ldd);
1432 
1433  /* Step over page if no options enabled */
1434  if (ldd->currentIdx == -1 )
1435  {
1436  gtk_assistant_set_current_page (assistant, num + 1);
1437  }
1438  else
1439  {
1440  g_assert( ldd->currentIdx >= 0 );
1441  g_assert( ldd->currentIdx <= ldd->ld.repayOptCount );
1442 
1443  rod = ldd->ld.repayOpts[ldd->currentIdx];
1444  str = g_string_sized_new( 32 );
1445  /* Translators: %s is "Taxes", or "Insurance", or similar */
1446  g_string_printf( str, _("Loan Repayment Option: \"%s\""), rod->name );
1447  gtk_assistant_set_page_title (assistant, page, str->str );
1448 
1449  /* copy in the relevant data from the currently-indexed option. */
1450  gtk_entry_set_text( ldd->payTxnName, rod->txnMemo );
1451  g_string_printf( str, "%0.2f", rod->amount );
1452  gtk_entry_set_text( ldd->payAmtEntry, str->str );
1453 
1454  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payUseEscrow),
1455  (ldd->ld.escrowAcct != NULL) );
1456 
1457  {
1458  g_signal_handlers_block_by_func( ldd->payUseEscrow,
1459  loan_pay_use_esc_toggle_cb,
1460  ldd );
1461 
1462  loan_pay_use_esc_setup( ldd,
1463  (ldd->ld.escrowAcct != NULL)
1464  && rod->throughEscrowP );
1465  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payUseEscrow),
1466  (rod->throughEscrowP
1467  && ldd->ld.escrowAcct != NULL) );
1468 
1469  g_signal_handlers_unblock_by_func( ldd->payUseEscrow,
1470  loan_pay_use_esc_toggle_cb,
1471  ldd );
1472  }
1473 
1474  {
1475  g_signal_handlers_block_by_func( ldd->paySpecSrcAcct,
1476  loan_pay_spec_src_toggle_cb,
1477  ldd );
1478  loan_pay_spec_src_setup( ldd, rod->specSrcAcctP );
1479  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->paySpecSrcAcct),
1480  rod->specSrcAcctP );
1481 
1482  g_signal_handlers_unblock_by_func( ldd->paySpecSrcAcct,
1483  loan_pay_spec_src_toggle_cb,
1484  ldd );
1485  }
1486 
1487  g_signal_handlers_block_by_func(ldd->payAcctToGAS, loan_pay_page_valid_cb, ldd );
1488  gnc_account_sel_set_account( ldd->payAcctToGAS, rod->to, FALSE );
1489  g_signal_handlers_unblock_by_func(ldd->payAcctToGAS, loan_pay_page_valid_cb, ldd );
1490 
1491 
1492  g_signal_handlers_block_by_func(ldd->payTxnFreqUniqRb, loan_pay_freq_toggle_cb, ldd );
1493  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqPartRb), !rod->FreqUniq );
1494  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb), rod->FreqUniq );
1495  g_signal_handlers_unblock_by_func(ldd->payTxnFreqUniqRb, loan_pay_freq_toggle_cb, ldd );
1496 
1497  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payFreqAlign), rod->FreqUniq );
1498 
1499  if ( rod->FreqUniq )
1500  {
1501  g_signal_handlers_disconnect_by_func( ldd->payGncFreq, loan_pay_page_valid_cb, ldd );
1502  gtk_container_remove( GTK_CONTAINER(ldd->payFreqAlign), GTK_WIDGET(ldd->payGncFreq) );
1503  ldd->payGncFreq = NULL;
1504  ldd->payGncFreq = GNC_FREQUENCY(gnc_frequency_new_from_recurrence( rod->schedule, rod->startDate ));
1505  gtk_container_add( GTK_CONTAINER(ldd->payFreqAlign), GTK_WIDGET(ldd->payGncFreq) );
1506  g_signal_connect (ldd->payGncFreq, "changed",
1507  G_CALLBACK (loan_pay_page_valid_cb), ldd);
1508  }
1509  g_string_free( str, TRUE );
1510  loan_pay_page_valid_cb(GTK_WIDGET(ldd->window), ldd);
1511  }
1512 }
1513 
1514 
1515 void
1516 loan_pay_page_valid_cb (GtkWidget *widget, gpointer user_data )
1517 {
1518  LoanAssistantData *ldd = user_data;
1519  GtkAssistant *assistant = GTK_ASSISTANT(ldd->window);
1520  gint num = gtk_assistant_get_current_page (assistant);
1521  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
1522 
1523  gtk_assistant_set_page_complete (assistant, page,
1524  ( loan_pay_complete (assistant, ldd) &&
1525  loan_pay_all_opt_valid (assistant, ldd )));
1526 }
1527 
1528 
1529 static
1530 void
1531 loan_pay_use_esc_setup( LoanAssistantData *ldd, gboolean newState )
1532 {
1533  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payEscToLabel), newState );
1534  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payEscFromLabel), newState );
1535  if ( newState )
1536  {
1537  g_signal_handlers_block_by_func( ldd->payAcctEscToGAS, loan_pay_page_valid_cb, ldd );
1538  g_signal_handlers_block_by_func( ldd->payAcctEscFromGAS, loan_pay_page_valid_cb, ldd );
1539  gnc_account_sel_set_account( ldd->payAcctEscToGAS, ldd->ld.escrowAcct, FALSE );
1540  gnc_account_sel_set_account( ldd->payAcctEscFromGAS, ldd->ld.escrowAcct, FALSE );
1541  g_signal_handlers_unblock_by_func( ldd->payAcctEscToGAS, loan_pay_page_valid_cb, ldd );
1542  g_signal_handlers_unblock_by_func( ldd->payAcctEscFromGAS, loan_pay_page_valid_cb, ldd );
1543  }
1544 }
1545 
1546 
1547 static
1548 void
1549 loan_pay_use_esc_toggle_cb( GtkToggleButton *tb, gpointer user_data )
1550 {
1551  gboolean newState;
1552  LoanAssistantData *ldd = user_data;
1553 
1554  newState = gtk_toggle_button_get_active( tb );
1555  loan_pay_use_esc_setup( ldd, newState );
1556 }
1557 
1558 
1559 static
1560 void
1561 loan_pay_spec_src_setup( LoanAssistantData *ldd, gboolean newState )
1562 {
1563  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payAcctFromLabel), newState );
1564  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payAcctFromGAS), newState );
1565  if ( newState )
1566  {
1567  g_signal_handlers_block_by_func( ldd->payAcctFromGAS, loan_pay_page_valid_cb, ldd );
1568  gnc_account_sel_set_account( ldd->payAcctFromGAS, ldd->ld.repayOpts[ldd->currentIdx]->from, FALSE );
1569  g_signal_handlers_unblock_by_func( ldd->payAcctFromGAS, loan_pay_page_valid_cb, ldd );
1570  }
1571  else
1572  {
1573  g_signal_handlers_block_by_func( ldd->payAcctFromGAS, loan_pay_page_valid_cb, ldd );
1574  gnc_account_sel_set_account( ldd->payAcctFromGAS, NULL, FALSE );
1575  ldd->ld.repayOpts[ldd->currentIdx]->from = NULL;
1576  g_signal_handlers_unblock_by_func( ldd->payAcctFromGAS, loan_pay_page_valid_cb, ldd );
1577  }
1578 }
1579 
1580 
1581 static
1582 void
1583 loan_pay_spec_src_toggle_cb( GtkToggleButton *tb, gpointer user_data )
1584 {
1585  gboolean newState;
1586  LoanAssistantData *ldd = user_data;
1587 
1588  newState = gtk_toggle_button_get_active( tb );
1589  loan_pay_spec_src_setup( ldd, newState );
1590 }
1591 
1592 
1593 static
1594 void
1595 loan_pay_freq_toggle_cb( GtkToggleButton *tb, gpointer user_data )
1596 {
1597  LoanAssistantData *ldd = user_data;
1598  RepayOptData *rod;
1599 
1600  g_assert( ldd->currentIdx >= 0 );
1601  g_assert( ldd->currentIdx <= ldd->ld.repayOptCount );
1602 
1603  rod = ldd->ld.repayOpts[ldd->currentIdx];
1604 
1605  rod->FreqUniq = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb) );
1606  gtk_widget_set_sensitive( GTK_WIDGET(ldd->payFreqAlign), rod->FreqUniq );
1607 
1608  if ( rod->FreqUniq )
1609  {
1610  if ( rod->schedule == NULL )
1611  {
1612  Recurrence *r = g_new0(Recurrence, 1);
1613 
1614  recurrenceSet(r, 1, PERIOD_MONTH, ldd->ld.startDate, WEEKEND_ADJ_NONE);
1615  rod->schedule = g_list_append(rod->schedule, r);
1616  }
1617  if ( rod->startDate == NULL )
1618  {
1619  rod->startDate = g_date_new();
1620  *rod->startDate = *ldd->ld.startDate;
1621  }
1622  g_signal_handlers_block_by_func( ldd->payGncFreq, loan_pay_page_valid_cb, ldd );
1623  gnc_frequency_setup_recurrence(ldd->payGncFreq, rod->schedule, rod->startDate);
1624  g_signal_handlers_unblock_by_func( ldd->payGncFreq, loan_pay_page_valid_cb, ldd );
1625  }
1626  else
1627  {
1628  if (rod->schedule)
1629  {
1630  recurrenceListFree(&rod->schedule);
1631  }
1632  if ( rod->startDate )
1633  {
1634  g_date_free( rod->startDate );
1635  rod->startDate = NULL;
1636  }
1637  }
1638 }
1639 
1640 
1641 static
1642 void
1643 loan_pay_next_button_cb( GtkButton *button, gpointer user_data )
1644 {
1645  int i;
1646  LoanAssistantData *ldd = user_data;
1647 
1648  /* save current data */
1649  if ( loan_pay_complete ( GTK_ASSISTANT(ldd->window), user_data ) != FALSE )
1650  {
1651  /* Go through opts list and select next enabled option. */
1652  for ( i = ldd->currentIdx + 1;
1653  (i < ldd->ld.repayOptCount)
1654  && !ldd->ld.repayOpts[i]->enabled; i++ )
1655  ;
1656  if ( i < ldd->ld.repayOptCount )
1657  {
1658  ldd->currentIdx = i;
1659  loan_pay_prep( GTK_ASSISTANT(ldd->window), user_data );
1660  }
1661  }
1662 }
1663 
1664 
1665 static
1666 void
1667 loan_pay_back_button_cb( GtkButton *button, gpointer user_data )
1668 {
1669  int i;
1670  LoanAssistantData *ldd = user_data;
1671 
1672  /* save current data */
1673  if ( loan_pay_complete ( GTK_ASSISTANT(ldd->window), user_data ) != FALSE)
1674  {
1675  /* go back through opts list and select next enabled options. */
1676  for ( i = ldd->currentIdx - 1;
1677  (i > -1) && !ldd->ld.repayOpts[i]->enabled;
1678  i-- )
1679  ;
1680  if ( i >= 0 )
1681  {
1682  ldd->currentIdx = i;
1683  loan_pay_prep( GTK_ASSISTANT(ldd->window), user_data );
1684  }
1685  }
1686 }
1687 
1688 
1689 static
1690 gboolean
1691 loan_pay_all_opt_valid ( GtkAssistant *assistant, gpointer user_data )
1692 {
1693  LoanAssistantData *ldd = user_data;
1694  int i;
1695  gboolean all_valid;
1696  all_valid = FALSE;
1697 
1698  /* Go through all option pages checking for valid enabled pages */
1699  for ( i = 0; (i < ldd->ld.repayOptCount); i++ )
1700  {
1701  if (ldd->ld.repayOpts[i]->enabled)
1702  {
1703  if (ldd->ld.repayOpts[i]->optValid)
1704  all_valid = TRUE;
1705  else
1706  all_valid = FALSE;
1707  }
1708  }
1709  return all_valid;
1710 }
1711 
1712 
1713 static
1714 gboolean
1715 loan_pay_complete( GtkAssistant *assistant, gpointer user_data )
1716 {
1717  gchar *tmpStr;
1718  LoanAssistantData *ldd = user_data;
1719  RepayOptData *rod;
1720 
1721  g_assert( ldd->currentIdx >= 0 );
1722  g_assert( ldd->currentIdx <= ldd->ld.repayOptCount );
1723  rod = ldd->ld.repayOpts[ ldd->currentIdx ];
1724 
1725  tmpStr = gtk_editable_get_chars( GTK_EDITABLE(ldd->payTxnName),
1726  0, -1 );
1727  if ( rod->txnMemo != NULL )
1728  {
1729  g_free( rod->txnMemo );
1730  }
1731  rod->txnMemo = tmpStr;
1732  tmpStr = NULL;
1733 
1734  tmpStr = gtk_editable_get_chars( GTK_EDITABLE(ldd->payAmtEntry),
1735  0, -1 );
1736  rod->amount = (float)strtod( tmpStr, NULL );
1737  g_free( tmpStr );
1738 
1739  rod->specSrcAcctP =
1740  gtk_toggle_button_get_active(
1741  GTK_TOGGLE_BUTTON(ldd->paySpecSrcAcct) );
1742 
1743  /* Test for Valid From Account */
1744  if ( rod->specSrcAcctP )
1745  {
1746  rod->from = gnc_account_sel_get_account( ldd->payAcctFromGAS );
1747  if ( rod->from == NULL )
1748  return FALSE;
1749  }
1750 
1751  /* Test for Valid To Account */
1752  rod->to = gnc_account_sel_get_account( ldd->payAcctToGAS );
1753  if ( rod->to == NULL )
1754  return FALSE;
1755 
1756  /* Set Page Valid */
1757  rod->optValid = TRUE;
1758 
1759  /* If Uniq Freq, then save to recurrence */
1760  if ( rod->FreqUniq )
1761  {
1762  if ( rod->startDate == NULL )
1763  {
1764  rod->startDate = g_date_new();
1765  }
1766  recurrenceListFree(&rod->schedule);
1767  gnc_frequency_save_to_recurrence(ldd->payGncFreq, &rod->schedule, rod->startDate);
1768 
1769  if (! rod->schedule )
1770  {
1771  return FALSE;
1772  }
1773  }
1774  return TRUE;
1775 }
1776 
1777 /************************************************************************/
1778 
1779 static
1780 void
1781 loan_rev_prep( GtkAssistant *assistant, gpointer user_data )
1782 {
1783  /* 3, here, does not include the Date column. */
1784  static const int BASE_COLS = 3;
1785  LoanAssistantData *ldd = user_data;
1786  GtkListStore *store;
1787  GtkCellRenderer *renderer;
1788  GtkTreeViewColumn *column;
1789  GType *types;
1790  int i;
1791  int col = 1;
1792 
1793  /* Make sure we saved last Payment Option */
1794  if (ldd->currentIdx != -1)
1795  loan_pay_complete(assistant, ldd);
1796 
1797  /* Cleanup old view */
1798  if ( ldd->revView != NULL )
1799  {
1800  gtk_widget_destroy( GTK_WIDGET(ldd->revView) );
1801  ldd->revView = NULL;
1802  }
1803 
1804  ldd->ld.revNumPmts = BASE_COLS;
1805  /* Get the correct number of repayment columns. */
1806  for ( i = 0; i < ldd->ld.repayOptCount; i++ )
1807  {
1808  ldd->ld.revRepayOptToColMap[i] = -1;
1809  if ( ! ldd->ld.repayOpts[i]->enabled )
1810  {
1811  continue;
1812  }
1813  /* not '+1' = there is no date column to be accounted for in
1814  * the mapping. */
1815  ldd->ld.revRepayOptToColMap[i] = ldd->ld.revNumPmts;
1816  ldd->ld.revNumPmts += 1;
1817  }
1818  /* '+1' for leading date col */
1819  types = g_new( GType, ldd->ld.revNumPmts + 1 );
1820  for ( i = 0; i < ldd->ld.revNumPmts + 1; i++ )
1821  types[i] = G_TYPE_STRING;
1822  store = gtk_list_store_newv(ldd->ld.revNumPmts + 1, types);
1823  g_free(types);
1824 
1825  ldd->revView = GTK_TREE_VIEW(
1826  gtk_tree_view_new_with_model( GTK_TREE_MODEL(store) ));
1827  g_object_unref(store);
1828 
1829  renderer = gtk_cell_renderer_text_new();
1830  column = gtk_tree_view_column_new_with_attributes(_("Date"), renderer,
1831  "text", LOAN_COL_DATE,
1832  NULL);
1833  gtk_tree_view_append_column(ldd->revView, column);
1834 
1835  renderer = gtk_cell_renderer_text_new();
1836  column = gtk_tree_view_column_new_with_attributes(_("Payment"), renderer,
1837  "text", LOAN_COL_PAYMENT,
1838  NULL);
1839  gtk_tree_view_append_column(ldd->revView, column);
1840 
1841  renderer = gtk_cell_renderer_text_new();
1842  column = gtk_tree_view_column_new_with_attributes(_("Principal"), renderer,
1843  "text", LOAN_COL_PRINCIPAL,
1844  NULL);
1845  gtk_tree_view_append_column(ldd->revView, column);
1846 
1847  renderer = gtk_cell_renderer_text_new();
1848  column = gtk_tree_view_column_new_with_attributes(_("Interest"), renderer,
1849  "text", LOAN_COL_INTEREST,
1850  NULL);
1851  gtk_tree_view_append_column(ldd->revView, column);
1852 
1853  /* move the appropriate names over into the title array */
1854  {
1855  for ( i = 0; i < ldd->ld.repayOptCount; i++ )
1856  {
1857  if ( ldd->ld.revRepayOptToColMap[i] == -1 )
1858  {
1859  continue;
1860  }
1861  renderer = gtk_cell_renderer_text_new();
1862  column = gtk_tree_view_column_new_with_attributes
1863  (ldd->ld.repayOpts[i]->name, renderer,
1864  "text", LOAN_COL_INTEREST + col,
1865  NULL);
1866  gtk_tree_view_append_column(ldd->revView, column);
1867  col++;
1868  }
1869  }
1870 
1871  gtk_container_add( GTK_CONTAINER(ldd->revScrollWin),
1872  GTK_WIDGET(ldd->revView) );
1873  gtk_widget_show( GTK_WIDGET(ldd->revView) );
1874 
1875  loan_rev_recalc_schedule( ldd );
1876 
1877  {
1878  GDate start, end;
1879  g_date_clear( &start, 1 );
1880  g_date_clear( &end, 1 );
1881  loan_rev_get_dates( ldd, &start, &end );
1882  loan_rev_update_view( ldd, &start, &end );
1883  }
1884 }
1885 
1886 
1887 static
1888 void
1889 loan_rev_range_opt_changed_cb( GtkComboBox *combo, gpointer user_data )
1890 {
1891  LoanAssistantData *ldd = user_data;
1892  int opt;
1893 
1894  opt = gtk_combo_box_get_active( ldd->revRangeOpt );
1895  gtk_widget_set_sensitive( GTK_WIDGET(ldd->revDateFrame),
1896  (opt == CUSTOM) );
1897  {
1898  GDate start, end;
1899  g_date_clear( &start, 1 );
1900  g_date_clear( &end, 1 );
1901  loan_rev_get_dates( ldd, &start, &end );
1902  loan_rev_update_view( ldd, &start, &end );
1903  }
1904 }
1905 
1906 
1907 static
1908 void
1909 loan_rev_range_changed_cb( GNCDateEdit *gde, gpointer user_data )
1910 {
1911  LoanAssistantData *ldd = user_data;
1912  {
1913  GDate start, end;
1914  g_date_clear( &start, 1 );
1915  g_date_clear( &end, 1 );
1916  loan_rev_get_dates( ldd, &start, &end );
1917  loan_rev_update_view( ldd, &start, &end );
1918  }
1919 }
1920 
1921 
1922 static
1923 void
1924 loan_rev_get_loan_range( LoanAssistantData *ldd, GDate *start, GDate *end )
1925 {
1926  int monthsTotal;
1927  struct tm *endDateMath;
1928 
1929  *start = *ldd->ld.startDate;
1930 
1931  endDateMath = g_new0( struct tm, 1 );
1932  g_date_to_struct_tm (ldd->ld.startDate, endDateMath);
1933  monthsTotal = ( (ldd->ld.numPer - 1)
1934  * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) );
1935  endDateMath->tm_mon += monthsTotal;
1936  gnc_gdate_set_time64 (end, gnc_mktime (endDateMath));
1937  g_free (endDateMath);
1938 }
1939 
1940 
1941 static
1942 void
1943 loan_rev_get_dates( LoanAssistantData *ldd, GDate *start, GDate *end )
1944 {
1945  int range = gtk_combo_box_get_active( ldd->revRangeOpt );
1946  switch ( range )
1947  {
1948  case CURRENT_YEAR:
1949  gnc_gdate_set_time64( start, gnc_time (NULL) );
1950  g_date_set_dmy( start, 1, G_DATE_JANUARY, g_date_get_year( start ) );
1951  g_date_set_dmy( end, 31, G_DATE_DECEMBER, g_date_get_year( start ) );
1952  break;
1953  case NOW_PLUS_ONE:
1954  gnc_gdate_set_time64( start, gnc_time (NULL) );
1955  *end = *start;
1956  g_date_add_years( end, 1 );
1957  break;
1958  case WHOLE_LOAN:
1959  loan_rev_get_loan_range( ldd, start, end );
1960  break;
1961  case CUSTOM:
1962  gnc_gdate_set_time64( start,
1963  gnc_date_edit_get_date( ldd->revStartDate ) );
1964  gnc_gdate_set_time64( end,
1965  gnc_date_edit_get_date( ldd->revEndDate ) );
1966  break;
1967  default:
1968  PERR( "Unknown review date range option %d", range );
1969  break;
1970  }
1971 
1972 }
1973 
1974 
1975 static
1976 void
1977 loan_rev_sched_list_free( gpointer data, gpointer user_data )
1978 {
1979  RevRepaymentRow *rrr = (RevRepaymentRow*)data;
1980  g_free( rrr->numCells );
1981  g_free( rrr );
1982 }
1983 
1984 
1985 static
1986 void
1987 loan_rev_hash_to_list( gpointer key, gpointer val, gpointer user_data )
1988 {
1989  GList **l = (GList**)user_data;
1990  RevRepaymentRow *rrr = g_new0( RevRepaymentRow, 1 );
1991  if ( !key || !val )
1992  {
1993  DEBUG( "%.8x, %.8x",
1994  GPOINTER_TO_UINT(key),
1995  GPOINTER_TO_UINT(val));
1996  return;
1997  }
1998  rrr->date = *(GDate*)key;
1999  rrr->numCells = (gnc_numeric*)val;
2000  *l = g_list_append( *l, (gpointer)rrr );
2001 }
2002 
2003 
2004 static
2005 void
2006 loan_rev_hash_free_date_keys( gpointer key, gpointer val, gpointer user_data )
2007 {
2008  g_free( (GDate*)key );
2009 }
2010 
2011 
2012 static
2013 void
2014 loan_rev_recalc_schedule( LoanAssistantData *ldd )
2015 {
2016  GDate start, end;
2017  gnc_numeric *rowNumData;
2018  GHashTable *repayment_schedule;
2019 
2020  g_date_clear( &start, 1 );
2021  g_date_clear( &end, 1 );
2022  loan_rev_get_loan_range( ldd, &start, &end );
2023 
2024  /* The repayment_schedule is a hash of GDates to
2025  * row-of-gnc_numeric[N] data, where N is the number of columns as
2026  * determined by the _prep function, and stored in
2027  * LoanData::revNumPmts. */
2028  repayment_schedule = g_hash_table_new(gnc_gdate_hash, gnc_gdate_equal);
2029 
2030  /* Do the master repayment */
2031  {
2032  GDate curDate, nextDate;
2033  GString *pmtFormula, *ppmtFormula, *ipmtFormula;
2034  int i;
2035  GHashTable *ivar;
2036 
2037  pmtFormula = g_string_sized_new( 64 );
2038  loan_get_pmt_formula( ldd, pmtFormula );
2039  ppmtFormula = g_string_sized_new( 64 );
2040  loan_get_ppmt_formula( ldd, ppmtFormula );
2041  ipmtFormula = g_string_sized_new( 64 );
2042  loan_get_ipmt_formula( ldd, ipmtFormula );
2043 
2044  ivar = g_hash_table_new( g_str_hash, g_str_equal );
2045  g_date_clear( &curDate, 1 );
2046  curDate = start;
2047  g_date_subtract_days( &curDate, 1 );
2048  g_date_clear(&nextDate, 1);
2049  recurrenceListNextInstance(ldd->ld.repayment_schedule, &curDate, &nextDate);
2050  for ( i = 1;
2051  g_date_valid( &nextDate )
2052  && g_date_compare( &nextDate, &end ) <= 0 ;
2053  i++,
2054  curDate = nextDate,
2055  recurrenceListNextInstance(ldd->ld.repayment_schedule,
2056  &curDate, &nextDate))
2057  {
2058  gnc_numeric ival;
2059  gnc_numeric val;
2060  char *eloc;
2061  rowNumData =
2062  (gnc_numeric*)g_hash_table_lookup( repayment_schedule,
2063  &curDate );
2064  if ( rowNumData == NULL)
2065  {
2066  int j;
2067  GDate *dateKeyCopy = g_date_new();
2068 
2069  *dateKeyCopy = curDate;
2070  rowNumData = g_new0( gnc_numeric, ldd->ld.revNumPmts );
2071  g_assert( rowNumData != NULL );
2072  for ( j = 0; j < ldd->ld.revNumPmts; j++ )
2073  {
2074  rowNumData[j] = gnc_numeric_error( GNC_ERROR_ARG );
2075  }
2076  g_hash_table_insert( repayment_schedule,
2077  (gpointer)dateKeyCopy,
2078  (gpointer)rowNumData );
2079  }
2080 
2081  /* evaluate the expressions given the correct
2082  * sequence number i */
2083  ival = gnc_numeric_create( i, 1 );
2084  g_hash_table_insert( ivar, "i", &ival );
2085 
2086  if ( ! gnc_exp_parser_parse_separate_vars(
2087  pmtFormula->str, &val, &eloc, ivar ) )
2088  {
2089  PERR( "pmt Parsing error at %s", eloc );
2090  continue;
2091  }
2093  rowNumData[0] = val;
2094 
2095  if ( ! gnc_exp_parser_parse_separate_vars(
2096  ppmtFormula->str, &val, &eloc, ivar ) )
2097  {
2098  PERR( "ppmt Parsing error at %s", eloc );
2099  continue;
2100  }
2102  rowNumData[1] = val;
2103 
2104  if ( ! gnc_exp_parser_parse_separate_vars(
2105  ipmtFormula->str, &val, &eloc, ivar ) )
2106  {
2107  PERR( "ipmt Parsing error at %s", eloc );
2108  continue;
2109  }
2111  rowNumData[2] = val;
2112  }
2113 
2114  g_string_free( ipmtFormula, TRUE );
2115  g_string_free( ppmtFormula, TRUE );
2116  g_string_free( pmtFormula, TRUE );
2117 
2118  g_hash_table_destroy( ivar );
2119  }
2120 
2121  /* Process any other enabled payments. */
2122  {
2123  int i;
2124  GDate curDate, nextDate;
2125  GList *schedule;
2126 
2127  for ( i = 0; i < ldd->ld.repayOptCount; i++ )
2128  {
2129  if ( ! ldd->ld.repayOpts[i]->enabled )
2130  continue;
2131 
2132  schedule
2133  = ( ldd->ld.repayOpts[i]->schedule != NULL
2134  ? ldd->ld.repayOpts[i]->schedule
2135  : ldd->ld.repayment_schedule );
2136 
2137  g_date_clear( &curDate, 1 );
2138  curDate = start;
2139  g_date_subtract_days( &curDate, 1 );
2140  g_date_clear(&nextDate, 1);
2141  recurrenceListNextInstance(schedule, &curDate, &nextDate );
2142  for ( ; g_date_valid( &nextDate )
2143  && g_date_compare( &nextDate, &end ) <= 0;
2144  curDate = nextDate,
2145  recurrenceListNextInstance(
2146  schedule, &curDate, &nextDate ) )
2147  {
2148  gint gncn_how =
2151  gnc_numeric val;
2152  rowNumData = (gnc_numeric*)g_hash_table_lookup( repayment_schedule,
2153  &curDate );
2154  if ( rowNumData == NULL )
2155  {
2156  int j;
2157  GDate *dateKeyCopy = g_date_new();
2158 
2159  *dateKeyCopy = curDate;
2160  rowNumData = g_new0( gnc_numeric, ldd->ld.revNumPmts );
2161  g_assert( rowNumData != NULL );
2162  for ( j = 0; j < ldd->ld.revNumPmts; j++ )
2163  {
2164  rowNumData[j] = gnc_numeric_error( GNC_ERROR_ARG );
2165  }
2166  g_hash_table_insert( repayment_schedule,
2167  (gpointer)dateKeyCopy,
2168  (gpointer)rowNumData );
2169  }
2170 
2171  val = double_to_gnc_numeric( (double)ldd->ld
2172  .repayOpts[i]
2173  ->amount,
2174  100, gncn_how );
2175  rowNumData[ ldd->ld.revRepayOptToColMap[i] ]
2176  = val;
2177  }
2178  }
2179  }
2180 
2181  /* Convert the GHashTable into a sorted GList in the LoanData */
2182  {
2183  if ( ldd->ld.revSchedule != NULL )
2184  {
2185  g_list_foreach( ldd->ld.revSchedule,
2186  loan_rev_sched_list_free,
2187  NULL );
2188  g_list_free( ldd->ld.revSchedule );
2189  ldd->ld.revSchedule = NULL;
2190  }
2191  g_hash_table_foreach( repayment_schedule, loan_rev_hash_to_list,
2192  &ldd->ld.revSchedule );
2193  g_hash_table_foreach( repayment_schedule, loan_rev_hash_free_date_keys,
2194  NULL );
2195  g_hash_table_destroy( repayment_schedule );
2196  ldd->ld.revSchedule =
2197  g_list_sort( ldd->ld.revSchedule, (GCompareFunc)g_date_compare );
2198  }
2199 }
2200 
2201 
2202 static
2203 void
2204 loan_rev_update_view( LoanAssistantData *ldd, GDate *start, GDate *end )
2205 {
2206  static gchar *NO_AMT_CELL_TEXT = " ";
2207  GList *l;
2208  GNCPrintAmountInfo pai;
2209  GtkListStore *store;
2210  GtkTreeIter iter;
2211 
2212  pai = gnc_default_price_print_info();
2213  pai.min_decimal_places = 2;
2214 
2215  store = GTK_LIST_STORE(gtk_tree_view_get_model( ldd->revView ));
2216 
2217  gtk_list_store_clear( store );
2218 
2219  for ( l = ldd->ld.revSchedule; l != NULL; l = l->next )
2220  {
2221  int i;
2222  gchar tmpBuf[50];
2223  RevRepaymentRow *rrr = (RevRepaymentRow*)l->data;
2224 
2225  if ( g_date_compare( &rrr->date, start ) < 0 )
2226  continue;
2227  if ( g_date_compare( &rrr->date, end ) > 0 )
2228  continue; /* though we can probably return, too. */
2229 
2230  gtk_list_store_append(store, &iter);
2231 
2232  qof_print_gdate( tmpBuf, MAX_DATE_LENGTH, &rrr->date );
2233  gtk_list_store_set( store, &iter, LOAN_COL_DATE, tmpBuf, -1 );
2234 
2235  for ( i = 0; i < ldd->ld.revNumPmts; i++ )
2236  {
2237  int numPrinted;
2238  if ( gnc_numeric_check( rrr->numCells[i] )
2239  == GNC_ERROR_ARG )
2240  {
2241  /* '+1' for the date cell */
2242  gtk_list_store_set( store, &iter,
2243  i + 1, NO_AMT_CELL_TEXT,
2244  -1);
2245  continue;
2246  }
2247 
2248  numPrinted = xaccSPrintAmount( tmpBuf, rrr->numCells[i], pai );
2249  g_assert( numPrinted < 50 );
2250  /* '+1' for the date cell */
2251  gtk_list_store_set( store, &iter,
2252  i + 1, tmpBuf,
2253  -1);
2254  }
2255 
2256  }
2257 }
2258 
2259 /************************* Worker functions *****************************/
2260 
2261 /* convert APR rate to simple rate based on formula r=q((1+i)^(1/q)-1) (r=interest rate, i=apr, q=compounding periods) */
2262 
2263 gfloat loan_apr_to_simple_formula (gfloat rate, gfloat compounding_periods)
2264 {
2265  /* float percent_to_frac; - redundant */
2266  gfloat simple_rate;
2267  /* percent_to_frac= compounding_periods/100; - redundant */
2268  simple_rate = compounding_periods * ((pow((1 + rate), (1 / compounding_periods))) - 1);
2269  return (simple_rate);
2270 }
2271 
2272 #define MAX_FORMULA 1024
2273 
2274 static
2275 void
2276 loan_get_formula_internal( LoanAssistantData *ldd, GString *gstr, const gchar* template )
2277 {
2278  gint rate_case;
2279  gfloat pass_thru_rate, period_rate;
2280  gfloat periods;
2281  gfloat principal;
2282  gchar formula[MAX_FORMULA];
2283 
2284  g_assert( ldd != NULL );
2285  g_assert( gstr != NULL );
2286 
2287  pass_thru_rate = ldd->ld.interestRate / 100;
2288  periods = (ldd->ld.numPer * (ldd->ld.perSize == GNC_MONTHS ? 1 : 12)) * 1.;
2289  principal = gnc_numeric_to_double(ldd->ld.principal);
2290 
2291  rate_case = ldd->ld.rateType;
2292  switch (rate_case)
2293  {
2294  case GNC_IRATE_SIMPLE:
2295  period_rate = pass_thru_rate;
2296  break;
2297  case GNC_IRATE_APR_DAILY:
2298  period_rate = loan_apr_to_simple_formula (pass_thru_rate, 365);
2299  break;
2300  case GNC_IRATE_APR_WEEKLY:
2301  period_rate = loan_apr_to_simple_formula (pass_thru_rate, 52);
2302  break;
2303  case GNC_IRATE_APR_MONTHLY:
2304  period_rate = loan_apr_to_simple_formula (pass_thru_rate, 12);
2305  break;
2306  case GNC_IRATE_APR_QUARTERLY:
2307  period_rate = loan_apr_to_simple_formula (pass_thru_rate, 4);
2308  break;
2309  case GNC_IRATE_APR_ANNUALLY:
2310  period_rate = loan_apr_to_simple_formula (pass_thru_rate, 1);
2311  break;
2312  default:
2313  period_rate = ldd->ld.interestRate / 100;
2314  break;
2315  }
2316 
2317  if (0 < strfmon (formula, MAX_FORMULA, template,
2318  period_rate, 12.0, periods, principal ))
2319  g_string_append (gstr, formula);
2320 }
2321 
2322 
2323 static
2324 void
2325 loan_get_pmt_formula( LoanAssistantData *ldd, GString *gstr )
2326 {
2327  loan_get_formula_internal (ldd, gstr, "pmt( %!.5i / %!0.2i : %!0.2i : %!0.2i : 0 : 0 )");
2328 }
2329 
2330 
2331 static
2332 void
2333 loan_get_ppmt_formula( LoanAssistantData *ldd, GString *gstr )
2334 {
2335  loan_get_formula_internal (ldd, gstr, "ppmt( %!.5i / %!0.2i : i : %!0.2i : %!0.2i : 0 : 0 )");
2336 }
2337 
2338 
2339 static
2340 void
2341 loan_get_ipmt_formula( LoanAssistantData *ldd, GString *gstr )
2342 {
2343  loan_get_formula_internal (ldd, gstr, "ipmt( %!.5i / %!0.2i : i : %!0.2i : %!0.2i : 0 : 0 )");
2344 }
2345 
2346 /******************* Scheduled Transaction Functions ********************/
2347 
2348 static int
2349 ld_calc_sx_instance_num(GDate *start_date, GList *schedule)
2350 {
2351  int instance_count;
2352  GDate next_date, today;
2353 
2354  g_date_clear(&next_date, 1);
2355  g_date_clear(&today, 1);
2356  gnc_gdate_set_time64 (&today, gnc_time (NULL));
2357 
2358  if (g_date_compare(start_date, &today) > 0)
2359  return 0;
2360 
2361  instance_count = -1;
2362  do
2363  {
2364  instance_count++;
2365  recurrenceListNextInstance(schedule, start_date, &next_date);
2366  }
2367  while (g_date_compare(&next_date, &today) < 0);
2368 
2369  return instance_count;
2370 }
2371 
2372 
2373 static
2374 void
2375 loan_tcSX_free( gpointer data, gpointer user_data )
2376 {
2377  toCreateSX *tcSX = (toCreateSX*)data;
2378  g_free( tcSX->name );
2379  if ( tcSX->mainTxn )
2380  gnc_ttinfo_free( tcSX->mainTxn );
2381  if ( tcSX->escrowTxn )
2382  gnc_ttinfo_free( tcSX->escrowTxn );
2383  g_free( tcSX );
2384 }
2385 
2386 
2392 static
2393 gint
2394 loan_find_ttsplit_with_acct( gconstpointer elt,
2395  gconstpointer crit )
2396 {
2397  TTSplitInfo *ttsi = (TTSplitInfo*)elt;
2398  return ( (gnc_ttsplitinfo_get_account( ttsi )
2399  == (Account*)crit) ? 0 : 1 );
2400 }
2401 
2402 
2406 static
2407 void
2408 loan_create_sx_from_tcSX( LoanAssistantData *ldd, toCreateSX *tcSX )
2409 {
2410  SchedXaction *sx;
2411  SchedXactions *sxes;
2412  GList *ttxnList;
2413 
2414  sx = xaccSchedXactionMalloc( gnc_get_current_book() );
2415  xaccSchedXactionSetName( sx, tcSX->name );
2416  gnc_sx_set_schedule(sx, tcSX->schedule);
2417  xaccSchedXactionSetStartDate( sx, &tcSX->start );
2418  xaccSchedXactionSetLastOccurDate( sx, &tcSX->last );
2419  xaccSchedXactionSetEndDate( sx, &tcSX->end );
2420  gnc_sx_set_instance_count( sx, tcSX->instNum );
2421 
2422  ttxnList = NULL;
2423  if ( tcSX->mainTxn )
2424  ttxnList = g_list_append( ttxnList, tcSX->mainTxn );
2425  if ( tcSX->escrowTxn )
2426  ttxnList = g_list_append( ttxnList, tcSX->escrowTxn );
2427 
2428  g_assert( ttxnList != NULL );
2429 
2430  xaccSchedXactionSetTemplateTrans( sx, ttxnList,
2431  gnc_get_current_book() );
2432 
2433  sxes = gnc_book_get_schedxactions(gnc_get_current_book());
2434  gnc_sxes_add_sx(sxes, sx);
2435  g_list_free( ttxnList );
2436  ttxnList = NULL;
2437 }
2438 
2439 
2445 static
2446 void
2447 ld_setup_repayment_sx( LoanAssistantData *ldd,
2448  RepayOptData *rod,
2449  toCreateSX *paymentSX,
2450  toCreateSX *tcSX )
2451 {
2452  /* In DoubleEntryAccounting-ease, this is what we're going to do,
2453  * below...
2454  *
2455  * if ( rep->escrow ) {
2456  * if ( rep->from ) {
2457  * a: paymentSX.main.splits += split( rep->fromAcct, repAmt )
2458  * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt
2459  * tcSX.escrow.split( rep->escrow ).debCred += repAmt
2460  * c1: tcSX.escrow.splits += split( rep->toAcct, +repAmt )
2461  * } else {
2462  * d: paymentSX.main.split( ldd->ld.repFromAcct ).debcred += -repAmt
2463  * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt
2464  * tcSX.escrow.splits += split( rep->escrow, -repAmt )
2465  * c1: tcSX.escrow.splits += split( rep->toAcct, +repAmt )
2466  * }
2467  * } else {
2468  * if ( rep->from ) {
2469  * a: paymentSX.main.splits += split( rep->fromAcct, -repAmt )
2470  * c2: paymentSX.main.splits += split( rep->toAcct, +repAmt )
2471  * } else {
2472  * d: paymentSX.main.split( ldd->ld.payFromAcct ).debcred += -repAmt
2473  * c2: paymentSX.main.splits += split( rep->toAcct, +repAmt )
2474  * }
2475  * }
2476  */
2477 
2478  /* Now, we refactor the common operations from the above out...
2479  *
2480  * fromSplit = NULL;
2481  * if ( rep->escrow ) {
2482  * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt
2483  * c1: ( toTTI = tcSX.escrow )
2484  * if ( rep->from ) {
2485  * a1: (fromSplit = NULL) paymentSX.main.splits += split( rep->fromAcct, repAmt )
2486  * b:
2487  * tcSX.escrow.split( rep->escrow ).debCred += repAmt
2488  * c1:
2489  * } else {
2490  * a2: (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) .debcred += -repAmt
2491  * b:
2492  * tcSX.escrow.splits += split( rep->escrow, -repAmt )
2493  * c1:
2494  * }
2495  * } else {
2496  * c2: ( toTTI = paymentSX.main )
2497  * if ( rep->from ) {
2498  * a1: (fromSplit = NULL) paymentSX.main.splits += split( rep->fromAcct, -repAmt )
2499  * c2:
2500  * } else {
2501  * a2: (fromSplit = paymentSX.main.split( ldd->ld.payFromAcct )).debcred += -repAmt
2502  * c2:
2503  * }
2504  * }
2505  * if ( fromSplit ) {
2506  * fromSplit.debCred += (-repAmt);
2507  * } else {
2508  * fromSplit = split( rep->fromAcct, -repAmt )
2509  * paymentSX.main.splits += fromSplit
2510  * }
2511  * toTTI.splits += split( rep->toAcct, +repAmt );
2512  */
2513 
2516  GString *gstr;
2517  GList *elt;
2518  TTSplitInfo *fromSplit = NULL;
2519  TTSplitInfo *ttsi;
2520  TTInfo *toTxn = NULL;
2521  GNCPrintAmountInfo pricePAI = gnc_default_price_print_info();
2522 #define AMTBUF_LEN 64
2523  gchar amtBuf[AMTBUF_LEN];
2524  gint GNCN_HOW = (GNC_HOW_DENOM_SIGFIGS(2) | GNC_HOW_RND_ROUND_HALF_UP);
2525 
2526  /* We're going to use this a lot, below, so just create it once. */
2527  xaccSPrintAmount( amtBuf,
2528  double_to_gnc_numeric( rod->amount, 100,
2529  GNCN_HOW ),
2530  pricePAI );
2531 
2532  if ( rod->throughEscrowP && ldd->ld.escrowAcct )
2533  {
2534  toTxn = tcSX->escrowTxn;
2535 
2536  /* Add the repayment amount into the string of the existing
2537  * ttsplit. */
2538  {
2539  elt = g_list_find_custom(
2540  gnc_ttinfo_get_template_splits( paymentSX->mainTxn ),
2541  ldd->ld.escrowAcct,
2542  loan_find_ttsplit_with_acct );
2543  g_assert( elt );
2544  ttsi = (TTSplitInfo*)elt->data;
2545  g_assert( ttsi );
2546  gstr = g_string_new( gnc_ttsplitinfo_get_debit_formula( ttsi ) );
2547  g_string_append_printf( gstr, " + %s", amtBuf );
2548  gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str );
2549  g_string_free( gstr, TRUE );
2550  gstr = NULL;
2551  ttsi = NULL;
2552  }
2553 
2554  if ( rod->from != NULL )
2555  {
2556  gchar *str;
2557 
2558  fromSplit = NULL;
2559 
2560  /* tcSX.escrow.split( rep->escrow ).debCred += repAmt */
2561  elt = g_list_find_custom(
2562  gnc_ttinfo_get_template_splits( tcSX->escrowTxn ),
2563  ldd->ld.escrowAcct,
2564  loan_find_ttsplit_with_acct );
2565  ttsi = NULL;
2566  if ( elt )
2567  {
2568  ttsi = (TTSplitInfo*)elt->data;
2569  }
2570  if ( !ttsi )
2571  {
2572  /* create split */
2573  ttsi = gnc_ttsplitinfo_malloc();
2574  gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo );
2575  gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct );
2576  gnc_ttinfo_append_template_split( tcSX->escrowTxn, ttsi );
2577  }
2578  if ( (str = (gchar*)gnc_ttsplitinfo_get_credit_formula( ttsi ))
2579  == NULL )
2580  {
2581  gstr = g_string_sized_new( 16 );
2582  }
2583  else
2584  {
2585  /* If we did get a split/didn't have to
2586  * create a split, then we need to add our
2587  * amount in rather than replace. */
2588  gstr = g_string_new( str );
2589  g_string_append_printf( gstr, " + " );
2590  }
2591  g_string_append_printf( gstr, "%s", amtBuf );
2592  gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str );
2593  g_string_free( gstr, TRUE );
2594  gstr = NULL;
2595  ttsi = NULL;
2596  }
2597  else
2598  {
2599  /* (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) */
2600  elt = g_list_find_custom(
2601  gnc_ttinfo_get_template_splits( paymentSX->mainTxn ),
2602  ldd->ld.repFromAcct,
2603  loan_find_ttsplit_with_acct );
2604  g_assert( elt );
2605  fromSplit = (TTSplitInfo*)elt->data;
2606 
2607  /* tcSX.escrow.splits += split( rep->escrow, -repAmt ) */
2608  ttsi = gnc_ttsplitinfo_malloc();
2609  gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo );
2610  gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct );
2611  gnc_ttsplitinfo_set_credit_formula( ttsi, amtBuf );
2612  gnc_ttinfo_append_template_split( tcSX->escrowTxn, ttsi );
2613  ttsi = NULL;
2614  }
2615  }
2616  else
2617  {
2618  toTxn = tcSX->mainTxn;
2619 
2620  if ( rod->from != NULL )
2621  {
2622  fromSplit = NULL;
2623  }
2624  else
2625  {
2626  /* (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) */
2627  elt = g_list_find_custom(
2628  gnc_ttinfo_get_template_splits( tcSX->mainTxn ),
2629  ldd->ld.repFromAcct,
2630  loan_find_ttsplit_with_acct );
2631  fromSplit = NULL;
2632  if ( elt )
2633  {
2634  /* This is conditionally true in the case of
2635  * a repayment on it's own schedule. */
2636  fromSplit = (TTSplitInfo*)elt->data;
2637  }
2638  }
2639  }
2640 
2641  if ( fromSplit != NULL )
2642  {
2643  /* Update the existing from-split. */
2644  gstr = g_string_new( gnc_ttsplitinfo_get_credit_formula( fromSplit ) );
2645  g_string_append_printf( gstr, " + %s", amtBuf );
2646  gnc_ttsplitinfo_set_credit_formula( fromSplit, gstr->str );
2647  g_string_free( gstr, TRUE );
2648  gstr = NULL;
2649 
2650  }
2651  else
2652  {
2653  TTInfo *tti;
2654  /* Create a new from-split. */
2655  ttsi = gnc_ttsplitinfo_malloc();
2656  gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo );
2657  if ( rod->from )
2658  {
2659  gnc_ttsplitinfo_set_account( ttsi, rod->from );
2660  }
2661  else
2662  {
2663  gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repFromAcct );
2664  }
2665  gnc_ttsplitinfo_set_credit_formula( ttsi, amtBuf );
2666  tti = tcSX->mainTxn;
2667  if ( rod->throughEscrowP )
2668  {
2669  tti = paymentSX->mainTxn;
2670  }
2671  gnc_ttinfo_append_template_split( tti, ttsi );
2672  ttsi = NULL;
2673  tti = NULL;
2674  }
2675 
2676  /* Add to-account split. */
2677  {
2678  ttsi = gnc_ttsplitinfo_malloc();
2679  gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo );
2680  gnc_ttsplitinfo_set_account( ttsi, rod->to );
2681  gnc_ttsplitinfo_set_debit_formula( ttsi, amtBuf );
2682  gnc_ttinfo_append_template_split( toTxn, ttsi );
2683  ttsi = NULL;
2684  }
2685 }
2686 
2687 
2702 static
2703 void
2704 loan_create_sxes( LoanAssistantData *ldd )
2705 {
2706  /* The main loan-payment SX.*/
2707  toCreateSX *paymentSX = NULL;
2708  /* A GList of any other repayment SXes with different schedule. */
2709  GList *repaySXes = NULL;
2710  /* The currently-being-referenced toCreateSX. */
2711  toCreateSX *tcSX;
2712  int i;
2713  TTInfo *ttxn;
2714  TTSplitInfo *ttsi;
2715  GString *gstr;
2716 
2717  paymentSX = g_new0( toCreateSX, 1 );
2718  paymentSX->name = g_strdup(ldd->ld.repMemo);
2719  paymentSX->start = *ldd->ld.startDate;
2720  paymentSX->last = *ldd->ld.repStartDate;
2721  g_date_subtract_months( &paymentSX->last, 1 );
2722  {
2723  paymentSX->end = *ldd->ld.repStartDate;
2724  g_date_add_months( &paymentSX->end, ldd->ld.numMonRemain - 1);
2725  }
2726 
2727  paymentSX->schedule = ldd->ld.repayment_schedule;
2728  /* Figure out the correct current instance-count for the txns in the
2729  * SX. */
2730  paymentSX->instNum =
2731  (ldd->ld.numPer * ( ldd->ld.perSize == GNC_YEARS ? 12 : 1 ))
2732  - ldd->ld.numMonRemain + 1;
2733 
2734  paymentSX->mainTxn = gnc_ttinfo_malloc();
2735  gnc_ttinfo_set_currency( paymentSX->mainTxn,
2737 
2738  {
2739  GString *payMainTxnDesc = g_string_sized_new( 32 );
2740  g_string_printf( payMainTxnDesc,
2741  "%s - %s",
2742  ldd->ld.repMemo,
2743  ( ldd->ld.escrowAcct == NULL
2744  ? _("Payment")
2745  : _("Escrow Payment") )
2746  );
2747 
2748  gnc_ttinfo_set_description( paymentSX->mainTxn,
2749  payMainTxnDesc->str );
2750  g_string_free( payMainTxnDesc, TRUE );
2751  }
2752 
2753  /* Create the basic txns and splits...
2754  *
2755  * ttxn <- mainTxn
2756  * srcAcct <- assets
2757  * if ( escrow ) {
2758  * realSrcAcct <- srcAcct
2759  * srcAcct <- escrow;
2760  * ttxn <- escrowTxn
2761  * main.splits += split( realSrcAcct, -pmt )
2762  * main.splits += split( escrow, pmt )
2763  * }
2764  * ttxn.splits += split( escrow, -pmt)
2765  * ttxn.splits += split( liability, ppmt )
2766  * ttxn.splits += split( expenses:interest, ipmt ) */
2767 
2768  {
2769  Account *srcAcct;
2770 
2771  ttxn = paymentSX->mainTxn;
2772  srcAcct = ldd->ld.repFromAcct;
2773  if ( ldd->ld.escrowAcct != NULL )
2774  {
2775  Account *realSrcAcct = srcAcct;
2776  srcAcct = ldd->ld.escrowAcct;
2777  gstr = g_string_sized_new( 32 );
2778  loan_get_pmt_formula( ldd, gstr );
2779  /* ttxn.splits += split( realSrcAcct, -pmt ); */
2780  {
2781  ttsi = gnc_ttsplitinfo_malloc();
2782  gnc_ttsplitinfo_set_memo( ttsi, ldd->ld.repMemo );
2783  gnc_ttsplitinfo_set_account( ttsi, realSrcAcct );
2784  gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str );
2785  gnc_ttinfo_append_template_split( ttxn, ttsi );
2786  ttsi = NULL;
2787  }
2788  /* ttxn.splits += split( escrowAcct, +pmt ); */
2789  {
2790  ttsi = gnc_ttsplitinfo_malloc();
2791  gnc_ttsplitinfo_set_memo( ttsi, ldd->ld.repMemo );
2792  gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct );
2793  gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str );
2794  gnc_ttinfo_append_template_split( ttxn, ttsi );
2795  ttsi = NULL;
2796  }
2797  g_string_free( gstr, TRUE );
2798  gstr = NULL;
2799  paymentSX->escrowTxn = gnc_ttinfo_malloc();
2800  gnc_ttinfo_set_currency( paymentSX->escrowTxn,
2802 
2803  {
2804  GString *escrowTxnDesc;
2805  escrowTxnDesc = g_string_new( ldd->ld.repMemo );
2806  g_string_append_printf( escrowTxnDesc, " - %s", _("Payment") );
2807  gnc_ttinfo_set_description( paymentSX->escrowTxn,
2808  escrowTxnDesc->str );
2809  g_string_free( escrowTxnDesc, TRUE );
2810  }
2811  ttxn = paymentSX->escrowTxn;
2812  }
2813  /* ttxn.splits += split( srcAcct, -pmt ); */
2814  {
2815  ttsi = gnc_ttsplitinfo_malloc();
2816  {
2817  gstr = g_string_new( ldd->ld.repMemo );
2818  g_string_append_printf( gstr, " - %s",
2819  _("Payment") );
2820  gnc_ttsplitinfo_set_memo( ttsi, gstr->str );
2821  g_string_free( gstr, TRUE );
2822  gstr = NULL;
2823  }
2824  gnc_ttsplitinfo_set_account( ttsi, srcAcct );
2825  gstr = g_string_sized_new( 32 );
2826  loan_get_pmt_formula( ldd, gstr );
2827  gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str );
2828  gnc_ttinfo_append_template_split( ttxn, ttsi );
2829  g_string_free( gstr, TRUE );
2830  gstr = NULL;
2831  ttsi = NULL;
2832  }
2833  /* ttxn.splits += split( ldd->ld.repPriAcct, +ppmt ); */
2834  {
2835  ttsi = gnc_ttsplitinfo_malloc();
2836  {
2837  gstr = g_string_new( ldd->ld.repMemo );
2838  g_string_append_printf( gstr, " - %s",
2839  _("Principal") );
2840  gnc_ttsplitinfo_set_memo( ttsi, gstr->str );
2841  g_string_free( gstr, TRUE );
2842  gstr = NULL;
2843  }
2844  gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repPriAcct );
2845  gstr = g_string_sized_new( 32 );
2846  loan_get_ppmt_formula( ldd, gstr );
2847  gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str );
2848  gnc_ttinfo_append_template_split( ttxn, ttsi );
2849  g_string_free( gstr, TRUE );
2850  gstr = NULL;
2851  ttsi = NULL;
2852  }
2853  /* ttxn.splits += split( ldd->ld.repIntAcct, +ipmt ); */
2854  {
2855  ttsi = gnc_ttsplitinfo_malloc();
2856  {
2857  gstr = g_string_new( ldd->ld.repMemo );
2858  g_string_append_printf( gstr, " - %s",
2859  _("Interest") );
2860  gnc_ttsplitinfo_set_memo( ttsi, gstr->str );
2861  g_string_free( gstr, TRUE );
2862  gstr = NULL;
2863  }
2864  gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repIntAcct );
2865  gstr = g_string_sized_new( 32 );
2866  loan_get_ipmt_formula( ldd, gstr );
2867  gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str );
2868  gnc_ttinfo_append_template_split( ttxn, ttsi );
2869  g_string_free( gstr, TRUE );
2870  gstr = NULL;
2871  ttsi = NULL;
2872  }
2873  }
2874  for ( i = 0; i < ldd->ld.repayOptCount; i++ )
2875  {
2876  RepayOptData *rod = ldd->ld.repayOpts[i];
2877  if ( ! rod->enabled )
2878  continue;
2879 
2880  tcSX = paymentSX;
2881  if ( rod->schedule != NULL )
2882  {
2883  tcSX = g_new0( toCreateSX, 1 );
2884  gstr = g_string_new( ldd->ld.repMemo );
2885  g_string_append_printf( gstr, " - %s",
2886  rod->name );
2887  tcSX->name = g_strdup(gstr->str);
2888  tcSX->start = *ldd->ld.startDate;
2889  tcSX->last = *ldd->ld.repStartDate;
2890  {
2891  tcSX->end = tcSX->last;
2892  g_date_add_months( &tcSX->end, ldd->ld.numMonRemain );
2893  }
2894  tcSX->schedule = rod->schedule;
2895  /* So it won't get destroyed when the close the
2896  * Assistant. */
2897  tcSX->instNum =
2898  ld_calc_sx_instance_num(&tcSX->start, rod->schedule);
2899  rod->schedule = NULL;
2900  tcSX->mainTxn = gnc_ttinfo_malloc();
2901  gnc_ttinfo_set_currency( tcSX->mainTxn,
2903  gnc_ttinfo_set_description( tcSX->mainTxn,
2904  gstr->str );
2905  tcSX->escrowTxn = gnc_ttinfo_malloc();
2906  gnc_ttinfo_set_currency( tcSX->escrowTxn,
2908  gnc_ttinfo_set_description( tcSX->escrowTxn,
2909  gstr->str );
2910 
2911  g_string_free( gstr, TRUE );
2912  gstr = NULL;
2913 
2914  repaySXes = g_list_append( repaySXes, tcSX );
2915 
2916  }
2917 
2918  /* repayment */
2919  ld_setup_repayment_sx( ldd, rod, paymentSX, tcSX );
2920  }
2921  /* Create the SXes */
2922  {
2923  GList *l;
2924 
2925  loan_create_sx_from_tcSX( ldd, paymentSX );
2926 
2927  for ( l = repaySXes; l; l = l->next )
2928  {
2929  loan_create_sx_from_tcSX( ldd, (toCreateSX*)l->data );
2930  }
2931  }
2932  /* Clean up. */
2933  loan_tcSX_free( paymentSX, NULL );
2934  g_list_foreach( repaySXes, loan_tcSX_free, NULL );
2935  g_list_free( repaySXes );
2936 }
2937 
2938 /************************ Assistant Functions ***************************/
2939 
2940 void
2941 loan_assistant_finish ( GtkAssistant *gtkassistant, gpointer user_data )
2942 {
2943  LoanAssistantData *ldd = user_data;
2944  loan_create_sxes( ldd );
2945 
2946 }
2947 
2948 
2949 void
2950 loan_assistant_cancel( GtkAssistant *gtkassistant, gpointer user_data )
2951 {
2952  LoanAssistantData *ldd = user_data;
2953  gnc_close_gui_component_by_data( DIALOG_LOAN_ASSISTANT_CM_CLASS, ldd );
2954 }
2955 
2956 
2957 void
2958 loan_assistant_close( GtkAssistant *gtkassistant, gpointer user_data )
2959 {
2960  LoanAssistantData *ldd = user_data;
2961  gnc_close_gui_component_by_data( DIALOG_LOAN_ASSISTANT_CM_CLASS, ldd );
2962 }
2963 
2964 
2965 void
2966 loan_assistant_prepare (GtkAssistant *assistant, GtkWidget *page,
2967  gpointer user_data)
2968 {
2969  gint currentpage = gtk_assistant_get_current_page(assistant);
2970 
2971  switch (currentpage)
2972  {
2973  case 1:
2974  /* Current page is info page */
2975  loan_info_prep (assistant, user_data);
2976  break;
2977  case 2:
2978  /* Current page is Options page */
2979  loan_opt_prep (assistant, user_data);
2980  break;
2981  case 3:
2982  /* Current page is Repayments page */
2983  loan_rep_prep (assistant, user_data);
2984  break;
2985  case 4:
2986  /* Current page is Repayments Options page */
2987  loan_pay_prep (assistant, user_data);
2988  break;
2989  case 5:
2990  /* Current page is Review page */
2991  loan_rev_prep (assistant, user_data);
2992  break;
2993  }
2994 }
2995 
2996 
2997 /********************************************************************\
2998  * gnc_ui_sx_loan_assistant_create *
2999  * opens up a window to start the loan Assistant *
3000  * *
3001 \********************************************************************/
3002 void
3003 gnc_ui_sx_loan_assistant_create (void)
3004 {
3005  LoanAssistantData *ldd;
3006  gint component_id;
3007 
3008  ldd = g_new0 (LoanAssistantData, 1);
3009 
3010  gnc_loan_assistant_create (ldd);
3011 
3012  component_id = gnc_register_gui_component (DIALOG_LOAN_ASSISTANT_CM_CLASS,
3013  NULL, loan_assistant_close_handler,
3014  ldd);
3015 
3016  gnc_gui_component_watch_entity_type (component_id,
3017  GNC_ID_ACCOUNT,
3018  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
3019 
3020  gtk_widget_show_all (ldd->window);
3021 
3022  gnc_window_adjust_for_screen (GTK_WINDOW(ldd->window));
3023 }
3024 
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
Definition: SchedXaction.c:565
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
GList * schedule
Date and Time handling routines.
gnc_numeric double_to_gnc_numeric(double n, gint64 denom, gint how)
utility functions for the GnuCash UI
#define DEBUG(format, args...)
Definition: qoflog.h:255
#define PERR(format, args...)
Definition: qoflog.h:237
gnc_commodity * gnc_default_currency(void)
Definition: gnc-ui-util.c:939
void gnc_tm_free(struct tm *time)
free a struct tm* created with gnc_localtime() or gnc_gmtime()
guint gnc_gdate_hash(gconstpointer gd)
gdouble gnc_numeric_to_double(gnc_numeric n)
Account handling public routines.
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
gboolean gnc_gdate_equal(gconstpointer gda, gconstpointer gdb)
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code)
TTInfo * mainTxn
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
#define MAX_DATE_LENGTH
Definition: gnc-date.h:106
void xaccSchedXactionSetTemplateTrans(SchedXaction *sx, GList *t_t_list, QofBook *book)
Set the schedxaction's template transaction.
struct tm * gnc_localtime(const time64 *secs)
fill out a time struct from a 64-bit time value.
All type declarations for the whole Gnucash engine.
int xaccSPrintAmount(char *bufp, gnc_numeric val, GNCPrintAmountInfo info)
Definition: gnc-ui-util.c:1437
GNCAccountType
Definition: Account.h:96
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
Definition: SchedXaction.c:581
TTInfo * escrowTxn
GDate helper routines.
time64 gnc_time(time64 *tbuf)
get the current local time
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Definition: SchedXaction.c:404
gint64 time64
Definition: gnc-date.h:83
Scheduled Transactions public handling routines.
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
Definition: SchedXaction.c:635
#define GNC_HOW_DENOM_SIGFIGS(n)
Definition: gnc-numeric.h:218
size_t qof_print_gdate(char *buf, size_t bufflen, const GDate *gd)
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_gdate_set_time64(GDate *gd, time64 time)