34 #include <glib/gi18n.h> 37 #include <glib/gstdio.h> 42 #include "gnc-gui-query.h" 44 #include "gncVendorP.h" 49 #include "gnc-exp-parser.h" 54 #include "gncIDSearch.h" 56 #include "dialog-bi-import-helper.h" 60 #include "dialog-invoice.h" 61 #include "business-gnome-utils.h" 64 #define FILL_IN_HELPER(match_name,column) \ 65 temp = g_match_info_fetch_named (match_info, match_name); \ 69 gtk_list_store_set (store, &iter, column, temp, -1); \ 71 } else gtk_list_store_set (store, &iter, column, "", -1); 74 static char * un_escape(
char *str);
98 GtkListStore * store, guint max_rows,
99 bi_import_stats * stats)
102 bi_import_stats stats_fallback;
107 gchar *line_utf8 = NULL;
109 GMatchInfo *match_info;
116 f = g_fopen (filename,
"rt");
120 return RESULT_OPEN_FAILED;
125 stats = &stats_fallback;
130 g_regex_new (parser_regexp, G_REGEX_EXTENDED | G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES, 0, &err);
136 errmsg = g_strdup_printf (_(
"Error in regular expression '%s':\n%s"),
137 parser_regexp, err->message);
141 dialog = gtk_message_dialog_new (NULL,
144 GTK_BUTTONS_OK,
"%s", errmsg);
145 gtk_dialog_run (GTK_DIALOG (dialog));
146 gtk_widget_destroy (dialog);
151 return RESULT_ERROR_IN_REGEXP;
155 stats->n_imported = 0;
156 stats->n_ignored = 0;
157 stats->ignored_lines = g_string_new (NULL);
158 #define buffer_size 1000 159 line = g_malloc0 (buffer_size);
162 || (stats->n_imported + stats->n_ignored < max_rows)))
166 if (!fgets (line, buffer_size, f))
170 if ((l > 0) && (line[l - 1] ==
'\n'))
174 line_utf8 = g_locale_to_utf8 (line, -1, NULL, NULL, NULL);
178 if (g_regex_match (regexpat, line_utf8, 0, &match_info))
184 gtk_list_store_append (store, &iter);
185 FILL_IN_HELPER (
"id", ID);
186 FILL_IN_HELPER (
"date_opened", DATE_OPENED);
187 FILL_IN_HELPER (
"owner_id", OWNER_ID);
188 FILL_IN_HELPER (
"billing_id", BILLING_ID);
189 FILL_IN_HELPER (
"notes", NOTES);
191 FILL_IN_HELPER (
"date", DATE);
192 FILL_IN_HELPER (
"desc", DESC);
193 FILL_IN_HELPER (
"action", ACTION);
194 FILL_IN_HELPER (
"account", ACCOUNT);
195 FILL_IN_HELPER (
"quantity", QUANTITY);
196 FILL_IN_HELPER (
"price", PRICE);
197 FILL_IN_HELPER (
"disc_type", DISC_TYPE);
198 FILL_IN_HELPER (
"disc_how", DISC_HOW);
199 FILL_IN_HELPER (
"discount", DISCOUNT);
200 FILL_IN_HELPER (
"taxable", TAXABLE);
201 FILL_IN_HELPER (
"taxincluded", TAXINCLUDED);
202 FILL_IN_HELPER (
"tax_table", TAX_TABLE);
204 FILL_IN_HELPER (
"date_posted", DATE_POSTED);
205 FILL_IN_HELPER (
"due_date", DUE_DATE);
206 FILL_IN_HELPER (
"account_posted", ACCOUNT_POSTED);
207 FILL_IN_HELPER (
"memo_posted", MEMO_POSTED);
208 FILL_IN_HELPER (
"accu_splits", ACCU_SPLITS);
214 g_string_append (stats->ignored_lines, line_utf8);
215 g_string_append_c (stats->ignored_lines,
'\n');
218 g_match_info_free (match_info);
226 g_regex_unref (regexpat);
230 if (stats == &stats_fallback)
232 g_string_free (stats->ignored_lines, TRUE);
270 GString * info, gchar *type)
272 GtkTreeIter iter, first_row_of_invoice;
273 gboolean valid, row_fixed, on_first_row_of_invoice, ignore_invoice;
274 gchar *
id = NULL, *date_opened = NULL, *date_posted = NULL, *due_date = NULL, *account_posted = NULL,
275 *owner_id = NULL, *date = NULL, *account = NULL, *quantity = NULL, *price = NULL;
279 gint row = 1, fixed_for_invoice = 0, invoice_line = 0;
282 DEBUG(
"date_format_string: %s",date_format_string);
285 n_rows_fixed = &dummy;
287 n_rows_ignored = &dummy;
293 running_id = g_string_new(
"");
294 ignore_invoice = FALSE;
295 on_first_row_of_invoice = TRUE;
297 g_string_append_printf (info, _(
"Validation…\n") );
300 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
307 if (on_first_row_of_invoice)
309 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
311 DATE_OPENED, &date_opened,
312 DATE_POSTED, &date_posted,
314 ACCOUNT_POSTED, &account_posted,
315 OWNER_ID, &owner_id, -1);
317 g_string_assign (running_id,
id);
318 first_row_of_invoice = iter;
321 if (strlen (
id) == 0)
325 ignore_invoice = TRUE;
326 g_string_append_printf (info,
327 _(
"Row %d: no invoice ID in first row of import file.\n"), row);
331 if (strlen (owner_id) == 0)
333 ignore_invoice = TRUE;
334 g_string_append_printf (info,
335 _(
"Row %d, invoice %s/%u: owner not set.\n"),
336 row,
id, invoice_line);
339 if (g_ascii_strcasecmp (type,
"BILL") == 0)
341 if (!gnc_search_vendor_on_id
342 (gnc_get_current_book (), owner_id))
345 ignore_invoice = TRUE;
346 g_string_append_printf (info,
347 _(
"Row %d, invoice %s/%u: vendor %s does not exist.\n"),
348 row,
id, invoice_line, owner_id);
351 else if (g_ascii_strcasecmp (type,
"INVOICE") == 0)
353 if (!gnc_search_customer_on_id
354 (gnc_get_current_book (), owner_id))
357 ignore_invoice = TRUE;
358 g_string_append_printf (info,
359 _(
"Row %d, invoice %s/%u: customer %s does not exist.\n"),
360 row,
id, invoice_line, owner_id);
364 if (strlen(date_posted) != 0)
367 if (!isDateValid(date_posted))
370 ignore_invoice = TRUE;
371 g_string_append_printf (info,
372 _(
"Row %d, invoice %s/%u: %s is not a valid posting date.\n"),
373 row,
id, invoice_line, date_posted);
376 if (!isDateValid(due_date))
379 g_string_append_printf (info,
380 _(
"Row %d, invoice %s/%u: %s is not a valid due date.\n"),
381 row,
id, invoice_line, due_date);
387 if (!isDateValid(due_date))
390 gtk_list_store_set (store, &iter, DUE_DATE,
399 (gnc_get_current_root_account (), account_posted);
402 ignore_invoice = TRUE;
403 g_string_append_printf (info,
404 _(
"Row %d, invoice %s/%u: account %s does not exist.\n"),
405 row,
id, invoice_line, account_posted);
409 if (g_ascii_strcasecmp (type,
"BILL") == 0)
414 ignore_invoice = TRUE;
415 g_string_append_printf (info,
416 _(
"Row %d, invoice %s/%u: account %s is not of type Accounts Payable.\n"),
417 row,
id, invoice_line, account_posted);
420 else if (g_ascii_strcasecmp (type,
"INVOICE") == 0)
424 ignore_invoice = TRUE;
425 g_string_append_printf (info,
426 _(
"Row %d, invoice %s/%u: account %s is not of type Accounts Receivable.\n"),
427 row,
id, invoice_line, account_posted);
434 if(!isDateValid(date_opened))
439 g_date_clear (&date, 1);
441 g_date_strftime (temp, 20, date_format_string, &date);
442 gtk_list_store_set (store, &iter, DATE_OPENED,
451 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
459 if (strlen (price) == 0)
462 ignore_invoice = TRUE;
463 g_string_append_printf (info,
464 _(
"Row %d, invoice %s/%u: price not set.\n"),
465 row,
id, invoice_line);
473 ignore_invoice = TRUE;
474 g_string_append_printf (info,
475 _(
"Row %d, invoice %s/%u: account %s does not exist.\n"),
476 row,
id, invoice_line, account);
484 if (strlen (quantity) == 0)
487 gtk_list_store_set (store, &iter, QUANTITY,
"1", -1);
492 if(!isDateValid(date))
495 gtk_list_store_set (store, &iter, DATE,
501 if (row_fixed) ++fixed_for_invoice;
504 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
505 if (valid) gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &
id, -1);
509 if (valid && strlen(
id) == 0)
511 strcpy(
id, running_id->str);
512 gtk_list_store_set (store, &iter, ID,
id, -1);
516 if (!valid || (valid && g_strcmp0 (
id, running_id->str) != 0))
521 iter = first_row_of_invoice;
525 valid = gtk_list_store_remove (store, &iter);
526 if (valid) gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &
id, -1);
528 while (valid && (g_strcmp0 (
id, running_id->str) == 0));
530 if (running_id->len != 0)
532 g_string_append_printf (info,
533 _(
"Error(s) in invoice %s, all rows of this invoice ignored.\n"),
538 g_string_append_printf (info,
539 _(
"Error(s) in invoice without id, all rows of this invoice ignored.\n"));
543 fixed_for_invoice = 0;
545 ignore_invoice = FALSE;
548 on_first_row_of_invoice = TRUE;
549 (*n_rows_fixed) += fixed_for_invoice;
550 fixed_for_invoice = 0;
554 g_free (date_opened);
555 g_free (date_posted);
557 g_free (account_posted);
560 else on_first_row_of_invoice = FALSE;
571 g_string_free (running_id, TRUE);
599 guint * n_invoices_created,
600 guint * n_invoices_updated,
601 guint * n_rows_ignored,
602 gchar * type, gchar * open_mode, GString * info,
605 gboolean valid, on_first_row_of_invoice, invoice_posted;
606 GtkTreeIter iter, first_row_of_invoice;
607 gchar *
id = NULL, *date_opened = NULL, *owner_id = NULL, *billing_id = NULL, *notes = NULL;
608 gchar *date = NULL, *desc = NULL, *action = NULL, *account = NULL, *quantity = NULL,
609 *price = NULL, *disc_type = NULL, *disc_how = NULL, *discount = NULL, *taxable = NULL,
610 *taxincluded = NULL, *tax_table = NULL;
611 gchar *date_posted = NULL, *due_date = NULL, *account_posted = NULL, *memo_posted = NULL,
612 *accumulatesplits = NULL;
616 gint day, month, year;
620 enum update {YES = GTK_RESPONSE_YES, NO = GTK_RESPONSE_NO, NOT_ASKED = GTK_RESPONSE_NONE} update;
627 g_return_if_fail (store && book);
629 g_return_if_fail ((g_ascii_strcasecmp (type,
"INVOICE") == 0) ||
630 (g_ascii_strcasecmp (type,
"BILL") == 0));
633 if (!n_invoices_created)
634 n_invoices_created = &dummy;
635 if (!n_invoices_updated)
636 n_invoices_updated = &dummy;
637 *n_invoices_created = 0;
638 *n_invoices_updated = 0;
642 on_first_row_of_invoice = TRUE;
643 running_id = g_string_new(
"");
645 g_string_append_printf (info,
"\n%s\n", _(
"Processing…") );
647 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
651 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
653 DATE_OPENED, &date_opened,
654 DATE_POSTED, &date_posted,
656 ACCOUNT_POSTED, &account_posted,
657 MEMO_POSTED, &memo_posted,
658 ACCU_SPLITS, &accumulatesplits,
660 BILLING_ID, &billing_id,
668 DISC_TYPE, &disc_type,
672 TAXINCLUDED, &taxincluded,
673 TAX_TABLE, &tax_table, -1);
675 if (on_first_row_of_invoice)
677 g_string_assign(running_id,
id);
678 first_row_of_invoice = iter;
680 if (g_ascii_strcasecmp (type,
"BILL") == 0)
681 invoice = gnc_search_bill_on_id (book,
id);
682 else if (g_ascii_strcasecmp (type,
"INVOICE") == 0)
683 invoice = gnc_search_invoice_on_id (book,
id);
684 DEBUG(
"Existing %s ID: %s\n", type, gncInvoiceGetID(invoice));
689 DEBUG(
"Creating a new : %s\n", type );
691 invoice = gncInvoiceCreate (book);
694 gncInvoiceBeginEdit (invoice);
695 gncInvoiceSetID (invoice,
id);
697 if (g_ascii_strcasecmp (type,
"BILL") == 0)
698 gncOwnerInitVendor (owner,
699 gnc_search_vendor_on_id (book, owner_id));
700 else if (g_ascii_strcasecmp (type,
"INVOICE") == 0)
701 gncOwnerInitCustomer (owner,
702 gnc_search_customer_on_id (book, owner_id));
703 gncInvoiceSetOwner (invoice, owner);
704 gncInvoiceSetCurrency (invoice, gncOwnerGetCurrency (owner));
706 gncInvoiceSetDateOpened (invoice,
708 gncInvoiceSetBillingID (invoice, billing_id ? billing_id :
"");
709 notes = un_escape(notes);
710 gncInvoiceSetNotes (invoice, notes ? notes :
"");
711 gncInvoiceSetActive (invoice, TRUE);
713 (*n_invoices_created)++;
714 g_string_append_printf (info, _(
"Invoice %s created.\n"),
id);
716 gncInvoiceCommitEdit (invoice);
722 if (update == NOT_ASKED)
724 dialog = gtk_message_dialog_new (parent,
729 _(
"Do you want to update existing bills/invoices?"));
730 update = gtk_dialog_run (GTK_DIALOG (dialog));
731 gtk_widget_destroy (dialog);
737 g_string_append_printf (info,_(
"Invoice %s not updated because it already exists.\n"),
id);
738 while (valid && g_strcmp0 (
id, running_id->str) == 0)
741 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
743 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &
id, -1);
745 on_first_row_of_invoice = TRUE;
749 if (gncInvoiceIsPosted (invoice))
752 g_string_append_printf (info,_(
"Invoice %s not updated because it is already posted.\n"),
id);
753 while (valid && g_strcmp0 (
id, running_id->str) == 0)
756 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
758 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &
id, -1);
760 on_first_row_of_invoice = TRUE;
764 (*n_invoices_updated)++;
765 g_string_append_printf (info, _(
"Invoice %s updated.\n"),
id);
770 entry = gncEntryCreate (book);
771 gncEntryBeginEdit(entry);
774 GDate *date = g_date_new_dmy(day, month, year);
779 gncEntrySetDateEntered(entry, today);
781 desc = un_escape(desc);
782 notes = un_escape(notes);
783 gncEntrySetDescription (entry, desc);
784 gncEntrySetAction (entry, action);
785 value = gnc_numeric_zero();
786 gnc_exp_parser_parse (quantity, &value, NULL);
791 if (g_ascii_strcasecmp (type,
"BILL") == 0)
793 gncEntrySetBillAccount (entry, acc);
794 value = gnc_numeric_zero();
795 gnc_exp_parser_parse (price, &value, NULL);
796 gncEntrySetBillPrice (entry, value);
797 gncEntrySetBillTaxable (entry, text2bool (taxable));
798 gncEntrySetBillTaxIncluded (entry, text2bool (taxincluded));
799 gncEntrySetBillTaxTable (entry, gncTaxTableLookupByName (book, tax_table));
802 else if (g_ascii_strcasecmp (type,
"INVOICE") == 0)
804 gncEntrySetNotes (entry, notes);
805 gncEntrySetInvAccount (entry, acc);
806 value = gnc_numeric_zero();
807 gnc_exp_parser_parse (price, &value, NULL);
808 gncEntrySetInvPrice (entry, value);
809 gncEntrySetInvTaxable (entry, text2bool (taxable));
810 gncEntrySetInvTaxIncluded (entry, text2bool (taxincluded));
811 gncEntrySetInvTaxTable (entry, gncTaxTableLookupByName (book, tax_table));
812 value = gnc_numeric_zero();
813 gnc_exp_parser_parse (discount, &value, NULL);
814 gncEntrySetInvDiscount (entry, value);
815 gncEntrySetInvDiscountType (entry, text2disc_type (disc_type));
816 gncEntrySetInvDiscountHow (entry, text2disc_how (disc_how));
817 gncInvoiceAddEntry (invoice, entry);
819 gncEntryCommitEdit(entry);
820 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
824 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &
id, -1);
828 if (g_strcmp0 (
id, running_id->str) == 0)
830 on_first_row_of_invoice = FALSE;
835 gtk_tree_model_get (GTK_TREE_MODEL (store), &first_row_of_invoice,
837 DATE_POSTED, &date_posted,
839 ACCOUNT_POSTED, &account_posted,
840 MEMO_POSTED, &memo_posted,
841 ACCU_SPLITS, &accumulatesplits, -1);
842 invoice_posted = FALSE;
844 if (strlen(date_posted) != 0)
847 GHashTable *foreign_currs;
851 gboolean scan_date_r;
852 scan_date_r =
qof_scan_date (date_posted, &day, &month, &year);
853 DEBUG(
"Invoice %s is marked to be posted because...",
id);
854 DEBUG(
"qof_scan_date = %d", scan_date_r);
855 if (g_ascii_strcasecmp (type,
"INVOICE") == 0)
861 curr_count = g_hash_table_size (foreign_currs);
862 DEBUG(
"curr_count = %d",curr_count);
867 (gnc_get_current_root_account (), account_posted);
877 text2bool (accumulatesplits),
879 PWARN(
"Invoice %s posted",
id);
880 invoice_posted = TRUE;
881 g_string_append_printf (info, _(
"Invoice %s posted.\n"),
id);
885 PWARN(
"Invoice %s NOT posted because currencies don't match",
id);
886 g_string_append_printf (info,_(
"Invoice %s NOT posted because currencies don't match.\n"),
id);
891 PWARN(
"Invoice %s NOT posted because it requires currency conversion.",
id);
892 g_string_append_printf (info,_(
"Invoice %s NOT posted because it requires currency conversion.\n"),
id);
894 g_hash_table_unref (foreign_currs);
898 PWARN(
"Invoice %s is NOT marked for posting",
id);
902 if (g_ascii_strcasecmp(open_mode,
"ALL") == 0
903 || (g_ascii_strcasecmp(open_mode,
"NOT_POSTED") == 0
906 iw = gnc_ui_invoice_edit (parent, invoice);
911 on_first_row_of_invoice = TRUE;
915 if (*n_invoices_updated + *n_invoices_created == 0)
916 g_string_append_printf (info, _(
"Nothing to process.\n"));
920 g_free (date_opened);
934 g_free (taxincluded);
936 g_free (date_posted);
938 g_free (account_posted);
939 g_free (memo_posted);
940 g_free (accumulatesplits);
942 g_string_free (running_id, TRUE);
953 gchar *newStr = NULL, *tmpstr = str;
954 int n = strlen (str), i;
955 newStr = g_malloc (n + 1);
956 memset (newStr, 0, n + 1);
958 for (i = 0; *tmpstr !=
'\0'; ++i, ++tmpstr)
960 newStr[i] = *tmpstr == quote ? *(++tmpstr) : *(tmpstr);
utility functions for the GnuCash UI
core import functions for invoice import plugin
void gncEntrySetQuantity(GncEntry *entry, gnc_numeric quantity)
Set the internal quantity without any conversion.
Date and Time handling routines.
utility functions for the GnuCash UI
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
#define DEBUG(format, args...)
Print a debugging message.
time64 gnc_dmy2time64(gint day, gint month, gint year)
Convert a day, month, and year to a time64, returning the first second of the day.
void gnc_gdate_set_today(GDate *gd)
Set a GDate to the current day.
Transaction * gncInvoicePostToAccount(GncInvoice *invoice, Account *acc, time64 post_date, time64 due_date, const char *memo, gboolean accumulatesplits, gboolean autopay)
Post this invoice to an account.
GHashTable * gncInvoiceGetForeignCurrencies(const GncInvoice *invoice)
Return an overview of amounts on this invoice that will be posted to accounts in currencies that are ...
#define PWARN(format, args...)
Log a warning.
QofDateFormat qof_date_format_get(void)
The qof_date_format_get routine returns the date format that the date printing will use when printing...
GncPluginPage * gnc_plugin_page_invoice_new(InvoiceWindow *iw)
Create a new "invoice" plugin page, given a pointer to an InvoiceWindow data structure.
void gncBillAddEntry(GncInvoice *bill, GncEntry *entry)
Call this function when adding an entry to a bill instead of an invoice.
void gncEntrySetDateGDate(GncEntry *entry, const GDate *date)
Set the date of this entry.
gnc_commodity * gnc_account_get_currency_or_parent(const Account *account)
Returns a gnc_commodity that is a currency, suitable for being a Transaction's currency.
Account * gnc_account_lookup_for_register(const Account *base_account, const char *name)
Retrieve the account matching the given name starting from the descendants of base_account.
Generic api to store and retrieve preferences.
gboolean qof_scan_date(const char *buff, int *day, int *month, int *year)
qof_scan_date Convert a string into day / month / year integers according to the current dateFormat v...
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
time64 gnc_time(time64 *tbuf)
get the current time
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Business Entry Interface.
const gchar * qof_date_format_get_string(QofDateFormat df)
This function returns a strftime formatting string for printing an all numeric date (e...
GncOwner * gncOwnerNew(void)
These two functions are mainly for the convenience of scheme code.