GnuCash  5.6-150-g038405b370+
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
dialog-customer-import.c
1 /*
2  * customer_import.c --
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 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <glib/gi18n.h>
33 #include <regex.h>
34 #include <glib.h>
35 #include <glib/gstdio.h>
36 
37 #include "gnc-ui.h"
38 #include "gnc-ui-util.h"
39 #include "gnc-gui-query.h"
40 #include "gncAddress.h"
41 #include "gncCustomerP.h"
42 #include "gncVendorP.h"
43 // query
44 #include "Query.h"
45 #include "qof.h"
46 #include "gncIDSearch.h"
47 
48 #include "dialog-customer-import.h"
49 
50 // private prototypes
51 //static GncCustomer *gnc_customer_import_searchCustomer (const gchar *id, QofBook *book);
52 
53 
54 
55 // perl regular expressions are available
56 
57 // this helper macro takes a regexp match and fills the model
58 #define FILL_IN_HELPER(match_name,column) \
59  temp = g_match_info_fetch_named (match_info, match_name); \
60  if (temp) \
61  { \
62  g_strstrip( temp ); \
63  gtk_list_store_set (store, &iter, column, temp, -1); \
64  g_free (temp); \
65  }
66 customer_import_result
67 gnc_customer_import_read_file (const gchar *filename, const gchar *parser_regexp, GtkListStore *store, guint max_rows, customer_import_stats *stats)
68 {
69  // some statistics
70  customer_import_stats stats_fallback;
71  FILE *f;
72 
73  // regexp
74  char *line;
75  gchar *line_utf8, *temp;
76  GMatchInfo *match_info;
77  GError *err;
78  GRegex *regexpat;
79 
80  // model
81  GtkTreeIter iter;
82 
83  f = g_fopen( filename, "rt" );
84  if (!f)
85  {
86  //gnc_error_dialog (NULL, _("File %s cannot be opened."), filename );
87  return CI_RESULT_OPEN_FAILED;
88  }
89 
90  // set up statistics
91  if (!stats)
92  stats = &stats_fallback;
93 
94  // compile the regular expression and check for errors
95  err = NULL;
96  regexpat = g_regex_new (parser_regexp, G_REGEX_EXTENDED | G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES, 0, &err);
97  if (err != NULL)
98  {
99  GtkWidget *dialog;
100  gchar *errmsg;
101 
102  errmsg = g_strdup_printf (_("Error in regular expression '%s':\n%s"),
103  parser_regexp, err->message);
104  g_error_free (err);
105  err = NULL;
106 
107  dialog = gtk_message_dialog_new (NULL,
108  GTK_DIALOG_MODAL,
109  GTK_MESSAGE_ERROR,
110  GTK_BUTTONS_OK,
111  "%s", errmsg);
112  gtk_dialog_run (GTK_DIALOG (dialog));
113  gtk_widget_destroy(dialog);
114  g_free (errmsg);
115  errmsg = 0;
116 
117  fclose (f);
118  return CI_RESULT_ERROR_IN_REGEXP;
119  }
120 
121  // start the import
122  stats->n_imported = 0;
123  stats->n_ignored = 0;
124  stats->ignored_lines = g_string_new (NULL);
125 #define buffer_size 1000
126  line = g_malloc0 (buffer_size);
127  while (!feof (f) && ((max_rows == 0) || (stats->n_imported + stats->n_ignored < max_rows)))
128  {
129  int l;
130  // read one line
131  if (!fgets (line, buffer_size, f))
132  break; // eof
133  // now strip the '\n' from the end of the line
134  l = strlen (line);
135  if ((l > 0) && (line[l - 1] == '\n'))
136  line[l - 1] = 0;
137 
138  // convert line from locale into utf8
139  line_utf8 = g_locale_to_utf8 (line, -1, NULL, NULL, NULL);
140 
141  // parse the line
142  match_info = NULL; // it seems, that in contrast to documentation, match_info is not always set -> g_match_info_free will segfault
143  if (g_regex_match (regexpat, line_utf8, 0, &match_info))
144  {
145  // match found
146  stats->n_imported++;
147 
148  // fill in the values
149  gtk_list_store_append (store, &iter);
150  FILL_IN_HELPER ("id", CI_ID);
151  FILL_IN_HELPER ("company", CI_COMPANY);
152  FILL_IN_HELPER ("name", CI_NAME);
153  FILL_IN_HELPER ("addr1", CI_ADDR1);
154  FILL_IN_HELPER ("addr2", CI_ADDR2);
155  FILL_IN_HELPER ("addr3", CI_ADDR3);
156  FILL_IN_HELPER ("addr4", CI_ADDR4);
157  FILL_IN_HELPER ("phone", CI_PHONE);
158  FILL_IN_HELPER ("fax", CI_FAX);
159  FILL_IN_HELPER ("email", CI_EMAIL);
160  FILL_IN_HELPER ("notes", CI_NOTES);
161  FILL_IN_HELPER ("shipname", CI_SHIPNAME);
162  FILL_IN_HELPER ("shipaddr1", CI_SHIPADDR1);
163  FILL_IN_HELPER ("shipaddr2", CI_SHIPADDR2);
164  FILL_IN_HELPER ("shipaddr3", CI_SHIPADDR3);
165  FILL_IN_HELPER ("shipaddr4", CI_SHIPADDR4);
166  FILL_IN_HELPER ("shipphone", CI_SHIPPHONE);
167  FILL_IN_HELPER ("shipfax", CI_SHIPFAX);
168  FILL_IN_HELPER ("shipemail", CI_SHIPEMAIL);
169  }
170  else
171  {
172  // ignore line
173  stats->n_ignored++;
174  g_string_append (stats->ignored_lines, line_utf8);
175  g_string_append_c (stats->ignored_lines, '\n');
176  }
177 
178  g_match_info_free (match_info);
179  match_info = 0;
180  g_free (line_utf8);
181  line_utf8 = 0;
182  }
183  g_free (line);
184  line = 0;
185 
186  g_regex_unref (regexpat);
187  regexpat = 0;
188  fclose (f);
189 
190  if (stats == &stats_fallback)
191  // stats are not requested -> free the string
192  g_string_free (stats->ignored_lines, TRUE);
193 
194  return CI_RESULT_OK;
195 }
196 
197 
198 
199 void
200 gnc_customer_import_fix_customers (GtkListStore *store, guint *fixed, guint *deleted, gchar * type)
201 {
202  GtkTreeIter iter;
203  gboolean valid;
204  gchar *company, *name, *addr1, *addr2, *addr3, *addr4;
205  guint dummy;
206 
207  // allow the call to this function with only GtkListeStore* specified
208  if (!fixed)
209  fixed = &dummy;
210  if (!deleted)
211  deleted = &dummy;
212 
213  *fixed = 0;
214  *deleted = 0;
215 
216  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter);
217  while (valid)
218  {
219  // Walk through the list, reading each row
220  gtk_tree_model_get (GTK_TREE_MODEL(store), &iter,
221  CI_COMPANY, &company,
222  CI_NAME, &name,
223  CI_ADDR1, &addr1,
224  CI_ADDR2, &addr2,
225  CI_ADDR3, &addr3,
226  CI_ADDR4, &addr4,
227  -1);
228 
229  // Company name is mandatory.
230  // If not provided, default the company name to the value of the field name.
231  if (strlen(company) == 0)
232  {
233  //But if the field name is also blank, then delete the row.
234  if (strlen(name) == 0)
235  {
236  // no fix possible -> delete row
237  valid = gtk_list_store_remove (store, &iter);
238  (*deleted)++;
239  continue;
240  }
241  else
242  {
243  // fix possible -> copy name to company
244  gtk_list_store_set (store, &iter, CI_COMPANY, name, -1);
245  (*fixed)++;
246  }
247  }
248 
249 
250  g_free (company);
251  g_free (name);
252  g_free (addr1);
253  g_free (addr2);
254  g_free (addr3);
255  g_free (addr4);
256 
257  valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
258  }
259 }
260 
261 void
262 gnc_customer_import_create_customers (GtkListStore *store, QofBook *book, guint *n_customers_created, guint *n_customers_updated, gchar * type)
263 {
264  gboolean valid;
265  GtkTreeIter iter;
266  gchar *id, *company, *name, *addr1, *addr2, *addr3, *addr4, *phone, *fax, *email;
267  gchar *notes, *shipname, *shipaddr1, *shipaddr2, *shipaddr3, *shipaddr4, *shipphone, *shipfax, *shipemail;
268  GncAddress *addr, *shipaddr;
269  guint dummy;
270  GncCustomer *customer;
271  GncVendor *vendor;
272  customer = NULL;
273  vendor = NULL;
274  addr = NULL;
275  shipaddr = NULL;
276  // these arguments are needed
277  g_return_if_fail (store && book);
278  printf("\nTYPE = %s\n", type);
279 
280  // allow to call this function without statistics
281  if (!n_customers_created)
282  n_customers_created = &dummy;
283  if (!n_customers_updated)
284  n_customers_updated = &dummy;
285  *n_customers_created = 0;
286  *n_customers_updated = 0;
287 
288  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter);
289  while (valid)
290  {
291  // Walk through the list, reading each row
292  gtk_tree_model_get (GTK_TREE_MODEL(store), &iter,
293  CI_ID, &id,
294  CI_COMPANY, &company,
295  CI_NAME, &name,
296  CI_ADDR1, &addr1,
297  CI_ADDR2, &addr2,
298  CI_ADDR3, &addr3,
299  CI_ADDR4, &addr4,
300  CI_PHONE, &phone,
301  CI_FAX, &fax,
302  CI_EMAIL, &email,
303  CI_NOTES, &notes,
304  CI_SHIPNAME, &shipname,
305  CI_SHIPADDR1, &shipaddr1,
306  CI_SHIPADDR2, &shipaddr2,
307  CI_SHIPADDR3, &shipaddr3,
308  CI_SHIPADDR4, &shipaddr4,
309  CI_SHIPPHONE, &shipphone,
310  CI_SHIPFAX, &shipfax,
311  CI_SHIPEMAIL, &shipemail,
312  -1);
313 
314  // Set the customer id if one has not been chosen
315  if (strlen (id) == 0)
316  {
317  if (g_ascii_strcasecmp (type, "CUSTOMER") == 0) id = gncCustomerNextID (book);
318  else if (g_ascii_strcasecmp (type, "VENDOR") == 0)id = gncVendorNextID (book);
319  //printf("ASSIGNED ID = %s\n",id);
320  }
321 
322  // Now save it off after checking if a vend/cust number doesn't already exist
323  {
324  if (g_ascii_strcasecmp (type, "CUSTOMER") == 0)
325  {
326  customer = gnc_search_customer_on_id (book, id);
327  if (!customer)
328  {
329  customer = gncCustomerCreate( book );
330  gncCustomerSetCurrency( customer, gnc_default_currency() );
331  (*n_customers_created)++;
332  }
333  else (*n_customers_updated)++;
334  }
335  else if (g_ascii_strcasecmp (type, "VENDOR") == 0)
336  {
337  vendor = gnc_search_vendor_on_id (book, id);
338  if ( !vendor)
339  {
340  vendor = gncVendorCreate( book );
341  gncVendorSetCurrency( vendor, gnc_default_currency() );
342  (*n_customers_created)++;
343  }
344  else (*n_customers_updated)++;
345  }
346 
347  if (g_ascii_strcasecmp (type, "CUSTOMER") == 0)
348  {
349  gncCustomerBeginEdit (customer);
350  gncCustomerSetID (customer, id);
351  gncCustomerSetName (customer, company);
352  gncCustomerSetNotes (customer, notes);
353  addr = gncCustomerGetAddr (customer);
354  shipaddr = gncCustomerGetShipAddr (customer);
355  }
356  else if (g_ascii_strcasecmp (type, "VENDOR") == 0)
357  {
358  gncVendorBeginEdit (vendor);
359  gncVendorSetID (vendor, id);
360  gncVendorSetName (vendor, company);
361  gncVendorSetNotes (vendor, notes);
362  addr = gncVendorGetAddr (vendor);
363  }
364  gncAddressSetName (addr, name);
365  gncAddressSetAddr1 (addr, addr1);
366  gncAddressSetAddr2 (addr, addr2);
367  gncAddressSetAddr3 (addr, addr3);
368  gncAddressSetAddr4 (addr, addr4);
369  gncAddressSetPhone (addr, phone);
370  gncAddressSetFax (addr, fax);
371  gncAddressSetEmail (addr, email);
372  if (g_ascii_strcasecmp (type, "CUSTOMER") == 0)
373  {
374  gncAddressSetName (shipaddr, shipname);
375  gncAddressSetAddr1 (shipaddr, shipaddr1);
376  gncAddressSetAddr2 (shipaddr, shipaddr2);
377  gncAddressSetAddr3 (shipaddr, shipaddr3);
378  gncAddressSetAddr4 (shipaddr, shipaddr4);
379  gncAddressSetPhone (shipaddr, shipphone);
380  gncAddressSetFax (shipaddr, shipfax);
381  gncAddressSetEmail (shipaddr, shipemail);
382  gncCustomerSetActive (customer, TRUE);
383  gncCustomerCommitEdit (customer);
384  }
385  else if (g_ascii_strcasecmp (type, "VENDOR") == 0)
386  {
387  gncVendorSetActive (vendor, TRUE);
388  gncVendorCommitEdit (vendor);
389  }
390  //printf("TYPE %s created with ID = %s.\n", type, id); // DEBUG
391  }
392 
393  g_free (id);
394  g_free (company);
395  g_free (name);
396  g_free (addr1);
397  g_free (addr2);
398  g_free (addr3);
399  g_free (addr4);
400  g_free (phone);
401  g_free (fax);
402  g_free (email);
403  g_free (notes);
404  g_free (shipname);
405  g_free (shipaddr1);
406  g_free (shipaddr2);
407  g_free (shipaddr3);
408  g_free (shipaddr4);
409  g_free (shipphone);
410  g_free (shipfax);
411  g_free (shipemail);
412  valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
413  }
414 }
415 
core import functions for customer import plugin
utility functions for the GnuCash UI
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
credit, discount and shipaddr are unique to GncCustomer id, name, notes, terms, addr, currency, taxtable, taxtable_override taxincluded, active and jobs are identical to ::GncVendor.
an Address object