GnuCash  5.6-150-g038405b370+
dialog-bi-import-gui.c
1 /*
2  * dialog-bi-import-gui.c -- Invoice Importer GUI
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, contact:
16  *
17  * Free Software Foundation Voice: +1-617-542-5942
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
19  * Boston, MA 02110-1301, USA gnu@gnu.org
20  */
21 
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 
35 #include <glib/gi18n.h>
36 
37 #include "gnc-ui.h"
38 #include "gnc-ui-util.h"
39 #include "gnc-component-manager.h"
40 #include "dialog-utils.h"
41 #include "gnc-gui-query.h"
42 #include "gnc-file.h"
43 #include "dialog-bi-import.h"
44 #include "dialog-bi-import-gui.h"
45 
47 {
48  GtkWindow *parent;
49  GtkWidget *dialog;
50  GtkWidget *tree_view;
51  GtkWidget *entryFilename;
52  GtkListStore *store;
53  gint component_id;
54  GString *regexp;
55  QofBook *book;
56  gchar *type;
57  gchar *open_mode;
58 };
59 
60 
61 // callback routines
62 void gnc_bi_import_gui_ok_cb (GtkWidget *widget, gpointer data);
63 void gnc_bi_import_gui_cancel_cb (GtkWidget *widget, gpointer data);
64 void gnc_bi_import_gui_help_cb (GtkWidget *widget, gpointer data);
65 void gnc_bi_import_gui_destroy_cb (GtkWidget *widget, gpointer data);
66 static void gnc_bi_import_gui_close_handler (gpointer user_data);
67 void gnc_bi_import_gui_buttonOpen_cb (GtkWidget *widget, gpointer data);
68 void gnc_bi_import_gui_filenameChanged_cb (GtkWidget *widget, gpointer data);
69 void gnc_bi_import_gui_option1_cb (GtkWidget *widget, gpointer data);
70 void gnc_bi_import_gui_option2_cb (GtkWidget *widget, gpointer data);
71 void gnc_bi_import_gui_option3_cb (GtkWidget *widget, gpointer data);
72 void gnc_bi_import_gui_option4_cb (GtkWidget *widget, gpointer data);
73 void gnc_bi_import_gui_option5_cb (GtkWidget *widget, gpointer data);
74 void gnc_bi_import_gui_open_mode_cb (GtkWidget *widget, gpointer data);
75 void gnc_import_gui_type_cb (GtkWidget *widget, gpointer data);
76 
77 #define UNUSED_VAR __attribute__ ((unused))
78 
79 static QofLogModule UNUSED_VAR log_module = G_LOG_DOMAIN; //G_LOG_BUSINESS;
80 
81 BillImportGui *
82 gnc_plugin_bi_import_showGUI (GtkWindow *parent)
83 {
84  BillImportGui *gui;
85  GtkBuilder *builder;
86  GList *glist;
87  GtkCellRenderer *renderer;
88  GtkTreeViewColumn *column;
89 
90  // if window exists already, activate it
91  glist = gnc_find_gui_components ("dialog-bi-import-gui", NULL, NULL);
92  if (glist)
93  {
94  // window found
95  gui = g_list_nth_data (glist, 0);
96  g_list_free (glist);
97 
98  gtk_window_set_transient_for(GTK_WINDOW(gui->dialog), GTK_WINDOW(parent));
99  gui->parent = parent;
100  gtk_window_present (GTK_WINDOW(gui->dialog));
101  return gui;
102  }
103 
104  // create new window
105  gui = g_new0 (BillImportGui, 1);
106  gui->type = "BILL"; // Set default type to match gui. really shouldn't be here TODO change me
107  gui->open_mode = "ALL";
108 
109  builder = gtk_builder_new();
110  gnc_builder_add_from_file (builder, "dialog-bi-import-gui.glade", "bi_import_dialog");
111  gui->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "bi_import_dialog"));
112  gtk_window_set_transient_for(GTK_WINDOW(gui->dialog), GTK_WINDOW(parent));
113  gui->parent = parent;
114  gui->tree_view = GTK_WIDGET(gtk_builder_get_object (builder, "treeview1"));
115  gui->entryFilename = GTK_WIDGET(gtk_builder_get_object (builder, "entryFilename"));
116 
117  // Set the name for this dialog so it can be easily manipulated with css
118  gtk_widget_set_name (GTK_WIDGET(gui->dialog), "gnc-id-bill-import");
119  gnc_widget_style_context_add_class (GTK_WIDGET(gui->dialog), "gnc-class-imports");
120 
121  gtk_window_set_transient_for (GTK_WINDOW (gui->dialog), parent);
122 
123  gui->book = gnc_get_current_book();
124 
125  gui->regexp = g_string_new ( "^(\\x{FEFF})?(?<id>[^;]*);(?<date_opened>[^;]*);(?<owner_id>[^;]*);(?<billing_id>[^;]*);(?<notes>[^;]*);(?<date>[^;]*);(?<desc>[^;]*);(?<action>[^;]*);(?<account>[^;]*);(?<quantity>[^;]*);(?<price>[^;]*);(?<disc_type>[^;]*);(?<disc_how>[^;]*);(?<discount>[^;]*);(?<taxable>[^;]*);(?<taxincluded>[^;]*);(?<tax_table>[^;]*);(?<date_posted>[^;]*);(?<due_date>[^;]*);(?<account_posted>[^;]*);(?<memo_posted>[^;]*);(?<accu_splits>[^;]*)$");
126 
127  // create model and bind to view
128  gui->store = gtk_list_store_new (N_COLUMNS,
129  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, // invoice settings
130  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, // entry settings
131  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); // autopost settings
132  gtk_tree_view_set_model( GTK_TREE_VIEW(gui->tree_view), GTK_TREE_MODEL(gui->store) );
133 #define CREATE_COLUMN(description,column_id) \
134  renderer = gtk_cell_renderer_text_new (); \
135  column = gtk_tree_view_column_new_with_attributes (description, renderer, "text", column_id, NULL); \
136  gtk_tree_view_column_set_resizable (column, TRUE); \
137  gtk_tree_view_append_column (GTK_TREE_VIEW (gui->tree_view), column);
138  CREATE_COLUMN (_("ID"), ID);
139  CREATE_COLUMN (_("Date Opened"), DATE_OPENED);
140  CREATE_COLUMN (_("Owner-ID"), OWNER_ID);
141  CREATE_COLUMN (_("Billing-ID"), BILLING_ID);
142  CREATE_COLUMN (_("Notes"), NOTES);
143 
144  CREATE_COLUMN (_("Date"), DATE);
145  CREATE_COLUMN (_("Description"), DESC);
146  CREATE_COLUMN (_("Action"), ACTION);
147  CREATE_COLUMN (_("Account"), ACCOUNT);
148  CREATE_COLUMN (_("Quantity"), QUANTITY);
149  CREATE_COLUMN (_("Price"), PRICE);
150  CREATE_COLUMN (_("Disc-type"), DISC_TYPE);
151  CREATE_COLUMN (_("Disc-how"), DISC_HOW);
152  CREATE_COLUMN (_("Discount"), DISCOUNT);
153  CREATE_COLUMN (_("Taxable"), TAXABLE);
154  CREATE_COLUMN (_("Taxincluded"), TAXINCLUDED);
155  CREATE_COLUMN (_("Tax-table"), TAX_TABLE);
156 
157  CREATE_COLUMN (_("Date Posted"), DATE_POSTED);
158  CREATE_COLUMN (_("Due Date"), DUE_DATE);
159  CREATE_COLUMN (_("Account-posted"), ACCOUNT_POSTED);
160  CREATE_COLUMN (_("Memo-posted"), MEMO_POSTED);
161  CREATE_COLUMN (_("Accu-splits"), ACCU_SPLITS);
162 
163  gui->component_id = gnc_register_gui_component ("dialog-bi-import-gui",
164  NULL,
165  gnc_bi_import_gui_close_handler,
166  gui);
167 
168  /* Setup signals */
169  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, gui);
170 
171  gtk_widget_show_all ( gui->dialog );
172 
173  g_object_unref(G_OBJECT(builder));
174 
175  return gui;
176 }
177 
178 static gchar *
179 gnc_plugin_bi_import_getFilename(GtkWindow *parent)
180 {
181  // prepare file import dialog
182  gchar *filename = NULL;
183  GList *filters;
184  GtkFileFilter *filter;
185  filters = NULL;
186  filter = gtk_file_filter_new ();
187  gtk_file_filter_set_name (filter, "comma separated values (*.csv)");
188  gtk_file_filter_add_pattern (filter, "*.csv");
189  filters = g_list_append( filters, filter );
190  filter = gtk_file_filter_new ();
191  gtk_file_filter_set_name (filter, "text files (*.txt)");
192  gtk_file_filter_add_pattern (filter, "*.txt");
193  filters = g_list_append( filters, filter );
194  filename = gnc_file_dialog(parent, _("Import Bills or Invoices from csv"), filters, NULL, GNC_FILE_DIALOG_IMPORT);
195 
196  return filename;
197 }
198 
199 void
200 gnc_bi_import_gui_ok_cb (GtkWidget *widget, gpointer data)
201 {
202  BillImportGui *gui = data;
203  gchar *filename = g_strdup( gtk_entry_get_text( GTK_ENTRY(gui->entryFilename) ) );
204  bi_import_stats stats;
205  bi_import_result res;
206  guint n_fixed, n_deleted, n_invoices_created, n_invoices_updated;
207  GString *info;
208 
209  // import
210  info = g_string_new("");
211 
212  gtk_list_store_clear (gui->store);
213  res = gnc_bi_import_read_file (filename, gui->regexp->str, gui->store, 0, &stats);
214  if (res == RESULT_OK)
215  {
216  gnc_bi_import_fix_bis (gui->store, &n_fixed, &n_deleted, info, gui->type);
217  gnc_bi_import_create_bis (gui->store, gui->book, &n_invoices_created, &n_invoices_updated, &n_deleted,
218  gui->type, gui->open_mode, info, gui->parent);
219  if (info->len > 0)
220  gnc_info_dialog (GTK_WINDOW (gui->dialog), "%s", info->str);
221  g_string_free( info, TRUE );
222  gnc_info_dialog (GTK_WINDOW (gui->dialog), _("Import:\n- rows ignored: %i\n- rows imported: %i\n\nValidation & processing:\n- rows fixed: %u\n- rows ignored: %u\n- invoices created: %u\n- invoices updated: %u"),
223  stats.n_ignored, stats.n_imported, n_fixed, n_deleted, n_invoices_created, n_invoices_updated);
224  if (stats.n_ignored > 0)
225  gnc_info2_dialog (gui->dialog, _("These lines were ignored during import"), stats.ignored_lines->str);
226 
227  g_string_free (stats.ignored_lines, TRUE);
228  gnc_close_gui_component (gui->component_id);
229  }
230  else if (res == RESULT_OPEN_FAILED)
231  {
232  gnc_error_dialog (GTK_WINDOW (gui->dialog), _("The input file can not be opened."));
233  }
234  else if (res == RESULT_ERROR_IN_REGEXP)
235  {
236  //gnc_error_dialog (GTK_WINDOW (gui->dialog), "The regular expression is faulty:\n\n%s", stats.err->str);
237  }
238 }
239 
240 void
241 gnc_bi_import_gui_cancel_cb (GtkWidget *widget, gpointer data)
242 {
243  BillImportGui *gui = data;
244 
245  gnc_close_gui_component (gui->component_id);
246 }
247 
248 void
249 gnc_bi_import_gui_help_cb (GtkWidget *widget, gpointer data)
250 {
251  BillImportGui *gui = data;
252  gnc_gnome_help (GTK_WINDOW(gui->dialog), DF_GUIDE, DL_IMPORT_BC);
253 }
254 
255 static void
256 gnc_bi_import_gui_close_handler (gpointer user_data)
257 {
258  BillImportGui *gui = user_data;
259 
260  gtk_widget_destroy (gui->dialog);
261  // gui has already been freed by this point.
262  // gui->dialog = NULL;
263 }
264 
265 void
266 gnc_bi_import_gui_destroy_cb (GtkWidget *widget, gpointer data)
267 {
268  BillImportGui *gui = data;
269 
270  gnc_suspend_gui_refresh ();
271  gnc_unregister_gui_component (gui->component_id);
272  gnc_resume_gui_refresh ();
273 
274  g_object_unref (gui->store);
275  g_string_free (gui->regexp, TRUE);
276  g_free (gui);
277 }
278 
279 void gnc_bi_import_gui_buttonOpen_cb (GtkWidget *widget, gpointer data)
280 {
281  gchar *filename = NULL;
282  BillImportGui *gui = data;
283 
284  filename = gnc_plugin_bi_import_getFilename (gnc_ui_get_gtk_window (widget));
285  if (filename)
286  {
287  //printf("Setting filename"); // debug
288  gtk_entry_set_text( GTK_ENTRY(gui->entryFilename), filename );
289  //printf("Set filename"); // debug
290  g_free( filename );
291  }
292 }
293 
294 void gnc_bi_import_gui_filenameChanged_cb (GtkWidget *widget, gpointer data)
295 {
296  BillImportGui *gui = data;
297  gchar *filename = g_strdup( gtk_entry_get_text( GTK_ENTRY(gui->entryFilename) ) );
298 
299  // generate preview
300  gtk_list_store_clear (gui->store);
301  gnc_bi_import_read_file (filename, gui->regexp->str, gui->store, 100, NULL);
302 
303  g_free( filename );
304 }
305 
306 // Semicolon separated
307 void gnc_bi_import_gui_option1_cb (GtkWidget *widget, gpointer data)
308 {
309  BillImportGui *gui = data;
310  if (!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ))
311  return;
312  g_string_assign (gui->regexp, "^(\\x{FEFF})?(?<id>[^;]*);(?<date_opened>[^;]*);(?<owner_id>[^;]*);(?<billing_id>[^;]*);(?<notes>[^;]*);(?<date>[^;]*);(?<desc>[^;]*);(?<action>[^;]*);(?<account>[^;]*);(?<quantity>[^;]*);(?<price>[^;]*);(?<disc_type>[^;]*);(?<disc_how>[^;]*);(?<discount>[^;]*);(?<taxable>[^;]*);(?<taxincluded>[^;]*);(?<tax_table>[^;]*);(?<date_posted>[^;]*);(?<due_date>[^;]*);(?<account_posted>[^;]*);(?<memo_posted>[^;]*);(?<accu_splits>[^;]*)$");
313  gnc_bi_import_gui_filenameChanged_cb (gui->entryFilename, gui);
314 }
315 
316 // Comma separated
317 void gnc_bi_import_gui_option2_cb (GtkWidget *widget, gpointer data)
318 {
319  BillImportGui *gui = data;
320  if (!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ))
321  return;
322  g_string_assign (gui->regexp, "^(\\x{FEFF})?(?<id>[^,]*),(?<date_opened>[^,]*),(?<owner_id>[^,]*),(?<billing_id>[^,]*),(?<notes>[^,]*),(?<date>[^,]*),(?<desc>[^,]*),(?<action>[^,]*),(?<account>[^,]*),(?<quantity>[^,]*),(?<price>[^,]*),(?<disc_type>[^,]*),(?<disc_how>[^,]*),(?<discount>[^,]*),(?<taxable>[^,]*),(?<taxincluded>[^,]*),(?<tax_table>[^,]*),(?<date_posted>[^,]*),(?<due_date>[^,]*),(?<account_posted>[^,]*),(?<memo_posted>[^,]*),(?<accu_splits>[^,]*)$");
323  gnc_bi_import_gui_filenameChanged_cb (gui->entryFilename, gui);
324 }
325 
326 // Semicolon separated with quotes
327 void gnc_bi_import_gui_option3_cb (GtkWidget *widget, gpointer data)
328 {
329  BillImportGui *gui = data;
330  if (!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ))
331  return;
332  g_string_assign (gui->regexp, "^(\\x{FEFF})?((?<id>[^\";]*)|\"(?<id>[^\"]*)\");((?<date_opened>[^\";]*)|\"(?<date_opened>[^\"]*)\");((?<owner_id>[^\";]*)|\"(?<owner_id>[^\"]*)\");((?<billing_id>[^\";]*)|\"(?<billing_id>[^\"]*)\");((?<notes>[^\";]*)|\"(?<notes>([^\"]|\"\")*)\");((?<date>[^\";]*)|\"(?<date>[^\"]*)\");((?<desc>[^\";]*)|\"(?<desc>([^\"]|\"\")*)\");((?<action>[^\";]*)|\"(?<action>[^\"]*)\");((?<account>[^\";]*)|\"(?<account>[^\"]*)\");((?<quantity>[^\";]*)|\"(?<quantity>[^\"]*)\");((?<price>[^\";]*)|\"(?<price>[^\"]*)\");((?<disc_type>[^\";]*)|\"(?<disc_type>[^\"]*)\");((?<disc_how>[^\";]*)|\"(?<disc_how>[^\"]*)\");((?<discount>[^\";]*)|\"(?<discount>[^\"]*)\");((?<taxable>[^\";]*)|\"(?<taxable>[^\"]*)\");((?<taxincluded>[^\";]*)|\"(?<taxincluded>[^\"]*)\");((?<tax_table>[^\";]*)|\"(?<tax_table>[^\"]*)\");((?<date_posted>[^\";]*)|\"(?<date_posted>[^\"]*)\");((?<due_date>[^\";]*)|\"(?<due_date>[^\"]*)\");((?<account_posted>[^\";]*)|\"(?<account_posted>[^\"]*)\");((?<memo_posted>[^\";]*)|\"(?<memo_posted>[^\"]*)\");((?<accu_splits>[^\";]*)|\"(?<accu_splits>[^\"]*)\")$");
333  gnc_bi_import_gui_filenameChanged_cb (gui->entryFilename, gui);
334 }
335 
336 // Comma separated with quote
337 void gnc_bi_import_gui_option4_cb (GtkWidget *widget, gpointer data)
338 {
339  BillImportGui *gui = data;
340  if (!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ))
341  return;
342  g_string_assign (gui->regexp, "^(\\x{FEFF})?((?<id>[^\",]*)|\"(?<id>[^\"]*)\"),((?<date_opened>[^\",]*)|\"(?<date_opened>[^\"]*)\"),((?<owner_id>[^\",]*)|\"(?<owner_id>[^\"]*)\"),((?<billing_id>[^\",]*)|\"(?<billing_id>[^\"]*)\"),((?<notes>[^\",]*)|\"(?<notes>([^\"]|\"\")*)\"),((?<date>[^\",]*)|\"(?<date>[^\"]*)\"),((?<desc>[^\",]*)|\"(?<desc>([^\"]|\"\")*)\"),((?<action>[^\",]*)|\"(?<action>[^\"]*)\"),((?<account>[^\",]*)|\"(?<account>[^\"]*)\"),((?<quantity>[^\",]*)|\"(?<quantity>[^\"]*)\"),((?<price>[^\",]*)|\"(?<price>[^\"]*)\"),((?<disc_type>[^\",]*)|\"(?<disc_type>[^\"]*)\"),((?<disc_how>[^\",]*)|\"(?<disc_how>[^\"]*)\"),((?<discount>[^\",]*)|\"(?<discount>[^\"]*)\"),((?<taxable>[^\",]*)|\"(?<taxable>[^\"]*)\"),((?<taxincluded>[^\",]*)|\"(?<taxincluded>[^\"]*)\"),((?<tax_table>[^\",]*)|\"(?<tax_table>[^\"]*)\"),((?<date_posted>[^\",]*)|\"(?<date_posted>[^\"]*)\"),((?<due_date>[^\",]*)|\"(?<due_date>[^\"]*)\"),((?<account_posted>[^\",]*)|\"(?<account_posted>[^\"]*)\"),((?<memo_posted>[^\",]*)|\"(?<memo_posted>[^\"]*)\"),((?<accu_splits>[^\",]*)|\"(?<accu_splits>[^\"]*)\")$");
343  gnc_bi_import_gui_filenameChanged_cb (gui->entryFilename, gui);
344 }
345 
346 // DIY regex.
347 void gnc_bi_import_gui_option5_cb (GtkWidget *widget, gpointer data)
348 {
349  BillImportGui *gui = data;
350  gchar *temp = NULL;
351  if (!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ))
352  return;
353  temp = gnc_input_dialog (0, _("Adjust regular expression used for import"), _("This regular expression is used to parse the import file. Modify according to your needs.\n"), gui->regexp->str);
354  if (temp)
355  {
356  g_string_assign (gui->regexp, temp);
357  g_free (temp);
358  gnc_bi_import_gui_filenameChanged_cb (gui->entryFilename, gui);
359  }
360 }
361 
362 void gnc_bi_import_gui_open_mode_cb (GtkWidget *widget, gpointer data)
363 {
364  BillImportGui *gui = data;
365  const gchar *name = NULL;
366  name = gtk_buildable_get_name(GTK_BUILDABLE(widget));
367  if (!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ))
368  return;
369  if (g_ascii_strcasecmp(name, "radiobuttonOpenAll") == 0)gui->open_mode = "ALL";
370  else if (g_ascii_strcasecmp(name, "radiobuttonOpenNotPosted") == 0)gui->open_mode = "NOT_POSTED";
371  else if (g_ascii_strcasecmp(name, "radiobuttonOpenNone") == 0)gui->open_mode = "NONE";
372 }
373 
374 
375 /*****************************************************************
376  * Set whether we are importing a bill, invoice, Customer or Vendor
377  * ****************************************************************/
378 void gnc_import_gui_type_cb (GtkWidget *widget, gpointer data)
379 {
380  BillImportGui *gui = data;
381  const gchar *name = NULL;
382  name = gtk_buildable_get_name(GTK_BUILDABLE(widget));
383  if (!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(widget) ))
384  return;
385  if (g_ascii_strcasecmp(name, "radiobuttonInvoice") == 0)gui->type = "INVOICE";
386  else if (g_ascii_strcasecmp(name, "radiobuttonBill") == 0)gui->type = "BILL";
387  //printf ("TYPE set to, %s\n",gui->type);
388 
389 }
390 
core import functions for invoice import plugin
GUI handling for bi-import plugin.
utility functions for the GnuCash UI
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
GtkWindow * gnc_ui_get_gtk_window(GtkWidget *widget)
Get a pointer to the widget&#39;s immediate top level GtkWindow.
void gnc_bi_import_fix_bis(GtkListStore *store, guint *n_rows_fixed, guint *n_rows_ignored, GString *info, gchar *type)
Adjusts and validates invoice import data.
void gnc_gnome_help(GtkWindow *parent, const char *file_name, const char *anchor)
Launch the systems default help browser, gnome&#39;s yelp for linux, and open to a given link within a gi...
bi_import_result gnc_bi_import_read_file(const gchar *filename, const gchar *parser_regexp, GtkListStore *store, guint max_rows, bi_import_stats *stats)
Imports a csv file with invoice data into a GtkListStore.
void gnc_bi_import_create_bis(GtkListStore *store, QofBook *book, guint *n_invoices_created, guint *n_invoices_updated, guint *n_rows_ignored, gchar *type, gchar *open_mode, GString *info, GtkWindow *parent)
Creates and updates invoices from validated import data.
BillImportGui * gnc_plugin_bi_import_showGUI(GtkWindow *parent)
File chooser.