GnuCash c935c2f+
Loading...
Searching...
No Matches
Files | Data Structures | Macros | Typedefs | Enumerations | Functions
Tools

Files

file  dialog-bi-import-gui.h
 GUI handling for bi-import plugin.
 
file  dialog-bi-import.h
 core import functions for invoice import plugin
 
file  gnc-plugin-bi-import.h
 Plugin registration of the bi-import module.
 
file  dialog-customer-import-gui.h
 GUI handling for customer import plugin.
 
file  dialog-customer-import.h
 core import functions for customer import plugin
 
file  gnc-plugin-customer-import.h
 Plugin registration of the customer_import module.
 

Data Structures

struct  bi_import_stats
 
struct  customer_import_stats
 

Macros

#define GNC_TYPE_PLUGIN_example   (gnc_plugin_example_get_type())
 
#define GNC_PLUGIN_EXAMPLE_NAME   "gnc-plugin-example"
 
#define GNC_TYPE_PLUGIN_BI_IMPORT   (gnc_plugin_bi_import_get_type())
 
#define GNC_PLUGIN_BI_IMPORT_NAME   "gnc-plugin-bi-import"
 
#define GNC_TYPE_PLUGIN_CUSTOMER_IMPORT   (gnc_plugin_customer_import_get_type())
 
#define GNC_PLUGIN_CUSTOMER_IMPORT_NAME   "gnc-plugin-customer-import"
 

Typedefs

typedef typedefG_BEGIN_DECLS struct _bi_import_gui BillImportGui
 
typedef enum _bi_import_result bi_import_result
 
typedef typedefG_BEGIN_DECLS struct _customer_import_gui CustomerImportGui
 
typedef enum _customer_import_result customer_import_result
 

Enumerations

enum  bi_import_model_columns {
  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 , N_COLUMNS
}
 
enum  _bi_import_result { RESULT_OK , RESULT_OPEN_FAILED , RESULT_ERROR_IN_REGEXP }
 
enum  customer_import_model_columns {
  CI_ID , CI_COMPANY , CI_NAME , CI_ADDR1 ,
  CI_ADDR2 , CI_ADDR3 , CI_ADDR4 , CI_PHONE ,
  CI_FAX , CI_EMAIL , CI_NOTES , CI_SHIPNAME ,
  CI_SHIPADDR1 , CI_SHIPADDR2 , CI_SHIPADDR3 , CI_SHIPADDR4 ,
  CI_SHIPPHONE , CI_SHIPFAX , CI_SHIPEMAIL , CI_N_COLUMNS
}
 
enum  _customer_import_result { CI_RESULT_OK , CI_RESULT_OPEN_FAILED , CI_RESULT_ERROR_IN_REGEXP }
 

Functions

GncPlugin * gnc_plugin_example_new (void)
 
void gnc_plugin_example_create_plugin (void)
 Create a new GncPluginexample object and register it.
 
BillImportGui * gnc_plugin_bi_import_showGUI (GtkWindow *parent)
 File chooser.
 
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_fix_bis (GtkListStore *store, guint *fixed, guint *deleted, GString *info, gchar *type)
 Adjusts and validates invoice import data.
 
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.
 
GncPlugin * gnc_plugin_bi_import_new (void)
 
void gnc_plugin_bi_import_create_plugin (void)
 Create a new GncPluginbi_import object and register it.
 
CustomerImportGui * gnc_plugin_customer_import_showGUI (GtkWindow *parent)
 File chooser.
 
customer_import_result gnc_customer_import_read_file (const gchar *filename, const gchar *parser_regexp, GtkListStore *store, guint max_rows, customer_import_stats *stats)
 
void gnc_customer_import_fix_customers (GtkListStore *store, guint *fixed, guint *deleted, gchar *type)
 
void gnc_customer_import_create_customers (GtkListStore *store, QofBook *book, guint *n_customers_created, guint *n_customers_updated, gchar *type)
 
GncPlugin * gnc_plugin_customer_import_new (void)
 
void gnc_plugin_customer_import_create_plugin (void)
 Create a new GncPlugincustomer_import object and register it.
 

Detailed Description

Macro Definition Documentation

◆ GNC_PLUGIN_BI_IMPORT_NAME

#define GNC_PLUGIN_BI_IMPORT_NAME   "gnc-plugin-bi-import"

Definition at line 43 of file gnc-plugin-bi-import.h.

◆ GNC_PLUGIN_CUSTOMER_IMPORT_NAME

#define GNC_PLUGIN_CUSTOMER_IMPORT_NAME   "gnc-plugin-customer-import"

Definition at line 43 of file gnc-plugin-customer-import.h.

◆ GNC_PLUGIN_EXAMPLE_NAME

#define GNC_PLUGIN_EXAMPLE_NAME   "gnc-plugin-example"

Definition at line 43 of file gnc-plugin.example.h.

◆ GNC_TYPE_PLUGIN_BI_IMPORT

#define GNC_TYPE_PLUGIN_BI_IMPORT   (gnc_plugin_bi_import_get_type())

Definition at line 40 of file gnc-plugin-bi-import.h.

◆ GNC_TYPE_PLUGIN_CUSTOMER_IMPORT

#define GNC_TYPE_PLUGIN_CUSTOMER_IMPORT   (gnc_plugin_customer_import_get_type())

Definition at line 40 of file gnc-plugin-customer-import.h.

◆ GNC_TYPE_PLUGIN_example

#define GNC_TYPE_PLUGIN_example   (gnc_plugin_example_get_type())

Definition at line 40 of file gnc-plugin.example.h.

Typedef Documentation

◆ bi_import_result

typedef enum _bi_import_result bi_import_result

Definition at line 55 of file dialog-bi-import.h.

◆ BillImportGui

typedef typedefG_BEGIN_DECLS struct _bi_import_gui BillImportGui

Definition at line 37 of file dialog-bi-import-gui.h.

◆ customer_import_result

typedef enum _customer_import_result customer_import_result

Definition at line 54 of file dialog-customer-import.h.

◆ CustomerImportGui

typedef typedefG_BEGIN_DECLS struct _customer_import_gui CustomerImportGui

Definition at line 37 of file dialog-customer-import-gui.h.

Enumeration Type Documentation

◆ _bi_import_result

enum _bi_import_result

Definition at line 49 of file dialog-bi-import.h.

50{
51 RESULT_OK,
52 RESULT_OPEN_FAILED,
53 RESULT_ERROR_IN_REGEXP,
54};

◆ _customer_import_result

enum _customer_import_result

Definition at line 48 of file dialog-customer-import.h.

49{
50 CI_RESULT_OK,
51 CI_RESULT_OPEN_FAILED,
52 CI_RESULT_ERROR_IN_REGEXP,
53};

◆ bi_import_model_columns

enum bi_import_model_columns

Definition at line 41 of file dialog-bi-import.h.

42{
43 ID, DATE_OPENED, OWNER_ID, BILLING_ID, NOTES, // invoice settings
44 DATE, DESC, ACTION, ACCOUNT, QUANTITY, PRICE, DISC_TYPE, DISC_HOW, DISCOUNT, TAXABLE, TAXINCLUDED, TAX_TABLE, // entry settings
45 DATE_POSTED, DUE_DATE, ACCOUNT_POSTED, MEMO_POSTED, ACCU_SPLITS, // autopost settings
46 N_COLUMNS
47};

◆ customer_import_model_columns

enum customer_import_model_columns

Definition at line 39 of file dialog-customer-import.h.

40{
41 CI_ID, CI_COMPANY,
42 CI_NAME, CI_ADDR1, CI_ADDR2, CI_ADDR3, CI_ADDR4, CI_PHONE, CI_FAX, CI_EMAIL,
43 CI_NOTES,
44 CI_SHIPNAME, CI_SHIPADDR1, CI_SHIPADDR2, CI_SHIPADDR3, CI_SHIPADDR4, CI_SHIPPHONE,
45 CI_SHIPFAX, CI_SHIPEMAIL, CI_N_COLUMNS
46};

Function Documentation

◆ gnc_bi_import_create_bis()

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.

Loops through the import data to create and update invoices. The first data row for an invoice is assumed to hold the header data.

If an invoice already exists, the user is asked, once per import, to confirm that invoices should be updated. If not confirmed, any rows for existing invoices are ignored. If confirmed, entries are added to existing invoices. Posted invoices, however, are never updated.

If the field date_posted is set, the system will attempt to also post the invoice. The system will not post the invoice if the entries of the invoice hold different currencies, or if the currency of the invoice differs from the currency of the account_posted.

As per user selection, the system displays tabs for either all affected invoices, all affected invoices not yet posted, or no invoices at all.

Definition at line 605 of file dialog-bi-import.c.

611{
612 gboolean valid, on_first_row_of_invoice, invoice_posted;
613 GtkTreeIter iter, first_row_of_invoice;
614 gchar *id = NULL, *date_opened = NULL, *owner_id = NULL, *billing_id = NULL, *notes = NULL;
615 gchar *date = NULL, *desc = NULL, *action = NULL, *account = NULL, *quantity = NULL,
616 *price = NULL, *disc_type = NULL, *disc_how = NULL, *discount = NULL, *taxable = NULL,
617 *taxincluded = NULL, *tax_table = NULL;
618 gchar *date_posted = NULL, *due_date = NULL, *account_posted = NULL, *memo_posted = NULL,
619 *accumulatesplits = NULL;
620 guint dummy;
621 GncInvoice *invoice;
622 GncEntry *entry;
623 gint day, month, year;
624 gnc_numeric value;
625 GncOwner *owner;
626 Account *acc = NULL;
627 enum update {YES = GTK_RESPONSE_YES, NO = GTK_RESPONSE_NO, NOT_ASKED = GTK_RESPONSE_NONE} update;
628 GtkWidget *dialog;
629 time64 today;
630 InvoiceWindow *iw;
631 GString *running_id;
632
633 // these arguments are needed
634 g_return_if_fail (store && book);
635 // logic of this function only works for bills or invoices
636 g_return_if_fail ((g_ascii_strcasecmp (type, "INVOICE") == 0) ||
637 (g_ascii_strcasecmp (type, "BILL") == 0));
638
639 // allow to call this function without statistics
640 if (!n_invoices_created)
641 n_invoices_created = &dummy;
642 if (!n_invoices_updated)
643 n_invoices_updated = &dummy;
644 *n_invoices_created = 0;
645 *n_invoices_updated = 0;
646
647 invoice = NULL;
648 update = NOT_ASKED;
649 on_first_row_of_invoice = TRUE;
650 running_id = g_string_new("");
651
652 g_string_append_printf (info, "\n%s\n", _("Processing…") );
653
654 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
655 while (valid)
656 {
657 // Walk through the list, reading each row
658 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
659 ID, &id,
660 DATE_OPENED, &date_opened,
661 DATE_POSTED, &date_posted, // if autoposting requested
662 DUE_DATE, &due_date, // if autoposting requested
663 ACCOUNT_POSTED, &account_posted, // if autoposting requested
664 MEMO_POSTED, &memo_posted, // if autoposting requested
665 ACCU_SPLITS, &accumulatesplits, // if autoposting requested
666 OWNER_ID, &owner_id,
667 BILLING_ID, &billing_id,
668 NOTES, &notes,
669 DATE, &date,
670 DESC, &desc,
671 ACTION, &action,
672 ACCOUNT, &account,
673 QUANTITY, &quantity,
674 PRICE, &price,
675 DISC_TYPE, &disc_type,
676 DISC_HOW, &disc_how,
677 DISCOUNT, &discount,
678 TAXABLE, &taxable,
679 TAXINCLUDED, &taxincluded,
680 TAX_TABLE, &tax_table, -1);
681
682 if (on_first_row_of_invoice)
683 {
684 g_string_assign(running_id, id);
685 first_row_of_invoice = iter;
686
687 if (g_ascii_strcasecmp (type, "BILL") == 0)
688 invoice = gnc_search_bill_on_id (book, id);
689 else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
690 invoice = gnc_search_invoice_on_id (book, id);
691 DEBUG( "Existing %s ID: %s\n", type, gncInvoiceGetID(invoice));
692
693 // If the search is empty then there is no existing invoice so make a new one
694 if (invoice == NULL)
695 {
696 DEBUG( "Creating a new : %s\n", type );
697 // new invoice
698 invoice = gncInvoiceCreate (book);
699 /* Protect against thrashing the DB and trying to write the invoice
700 * record prematurely */
701 gncInvoiceBeginEdit (invoice);
702 gncInvoiceSetID (invoice, id);
703 owner = gncOwnerNew ();
704 if (g_ascii_strcasecmp (type, "BILL") == 0)
705 gncOwnerInitVendor (owner,
706 gnc_search_vendor_on_id (book, owner_id));
707 else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
708 gncOwnerInitCustomer (owner,
709 gnc_search_customer_on_id (book, owner_id));
710 gncInvoiceSetOwner (invoice, owner);
711 gncInvoiceSetCurrency (invoice, gncOwnerGetCurrency (owner)); // Set the invoice currency based on the owner
712 qof_scan_date (date_opened, &day, &month, &year);
713 gncInvoiceSetDateOpened (invoice,
714 gnc_dmy2time64 (day, month, year));
715 gncInvoiceSetBillingID (invoice, billing_id ? billing_id : "");
716 notes = un_escape(notes);
717 gncInvoiceSetNotes (invoice, notes ? notes : "");
718 gncInvoiceSetActive (invoice, TRUE);
719 //if (g_ascii_strcasecmp(type,"INVOICE"))gncInvoiceSetBillTo( invoice, billto );
720 (*n_invoices_created)++;
721 g_string_append_printf (info, _("Invoice %s created.\n"),id);
722
723 gncInvoiceCommitEdit (invoice);
724 }
725 else // Dealing with an existing invoice.
726 {
727 // For the first existing invoice in the import file,
728 // ask the user to confirm update of existing invoices.
729 if (update == NOT_ASKED)
730 {
731 dialog = gtk_message_dialog_new (parent,
732 GTK_DIALOG_MODAL,
733 GTK_MESSAGE_ERROR,
734 GTK_BUTTONS_YES_NO,
735 "%s",
736 _("Do you want to update existing bills/invoices?"));
737 update = gtk_dialog_run (GTK_DIALOG (dialog));
738 gtk_widget_destroy (dialog);
739 }
740
741 if (update == NO)
742 {
743 // If the user does not want to update existing invoices, ignore all rows of the invoice.
744 g_string_append_printf (info,_("Invoice %s not updated because it already exists.\n"),id);
745 while (valid && g_strcmp0 (id, running_id->str) == 0)
746 {
747 (*n_rows_ignored)++;
748 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
749 if (valid)
750 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &id, -1);
751 }
752 on_first_row_of_invoice = TRUE;
753 continue;
754 }
755
756 if (gncInvoiceIsPosted (invoice))
757 {
758 // If the invoice is already posted, ignore all rows of the invoice.
759 g_string_append_printf (info,_("Invoice %s not updated because it is already posted.\n"),id);
760 while (valid && g_strcmp0 (id, running_id->str) == 0)
761 {
762 (*n_rows_ignored)++;
763 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
764 if (valid)
765 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &id, -1);
766 }
767 on_first_row_of_invoice = TRUE;
768 continue;
769 }
770
771 (*n_invoices_updated)++;
772 g_string_append_printf (info, _("Invoice %s updated.\n"),id);
773 }
774 }
775
776 // Add entry to invoice/bill
777 entry = gncEntryCreate (book);
778 gncEntryBeginEdit(entry);
779 qof_scan_date (date, &day, &month, &year);
780 {
781 GDate *date = g_date_new_dmy(day, month, year);
782 gncEntrySetDateGDate (entry, date);
783 g_date_free (date);
784 }
785 today = gnc_time (NULL);
786 gncEntrySetDateEntered(entry, today);
787 // Remove escaped quotes
788 desc = un_escape(desc);
789 notes = un_escape(notes);
790 gncEntrySetDescription (entry, desc);
791 gncEntrySetAction (entry, action);
792 value = gnc_numeric_zero();
793 gnc_exp_parser_parse (quantity, &value, NULL);
794 gncEntrySetQuantity (entry, value);
795 acc = gnc_account_lookup_for_register (gnc_get_current_root_account (),
796 account);
797
798 if (g_ascii_strcasecmp (type, "BILL") == 0)
799 {
800 gncEntrySetBillAccount (entry, acc);
801 value = gnc_numeric_zero();
802 gnc_exp_parser_parse (price, &value, NULL);
803 gncEntrySetBillPrice (entry, value);
804 gncEntrySetBillTaxable (entry, text2bool (taxable));
805 gncEntrySetBillTaxIncluded (entry, text2bool (taxincluded));
806 gncEntrySetBillTaxTable (entry, gncTaxTableLookupByName (book, tax_table));
807 gncBillAddEntry (invoice, entry);
808 }
809 else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
810 {
811 gncEntrySetNotes (entry, notes);
812 gncEntrySetInvAccount (entry, acc);
813 value = gnc_numeric_zero();
814 gnc_exp_parser_parse (price, &value, NULL);
815 gncEntrySetInvPrice (entry, value);
816 gncEntrySetInvTaxable (entry, text2bool (taxable));
817 gncEntrySetInvTaxIncluded (entry, text2bool (taxincluded));
818 gncEntrySetInvTaxTable (entry, gncTaxTableLookupByName (book, tax_table));
819 value = gnc_numeric_zero();
820 gnc_exp_parser_parse (discount, &value, NULL);
821 gncEntrySetInvDiscount (entry, value);
822 gncEntrySetInvDiscountType (entry, text2disc_type (disc_type));
823 gncEntrySetInvDiscountHow (entry, text2disc_how (disc_how));
824 gncInvoiceAddEntry (invoice, entry);
825 }
826 gncEntryCommitEdit(entry);
827 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
828 // handle auto posting of invoices
829
830 if (valid)
831 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &id, -1);
832 else
833 id = NULL;
834
835 if (g_strcmp0 (id, running_id->str) == 0) // The next row is for the same invoice.
836 {
837 on_first_row_of_invoice = FALSE;
838 }
839 else // The next row is for a new invoice; try to post the invoice.
840 {
841 // Use posting values from the first row of this invoice.
842 gtk_tree_model_get (GTK_TREE_MODEL (store), &first_row_of_invoice,
843 ID, &id,
844 DATE_POSTED, &date_posted,
845 DUE_DATE, &due_date,
846 ACCOUNT_POSTED, &account_posted,
847 MEMO_POSTED, &memo_posted,
848 ACCU_SPLITS, &accumulatesplits, -1);
849 invoice_posted = FALSE;
850
851 if (strlen(date_posted) != 0)
852 {
853 // autopost this invoice
854 GHashTable *foreign_currs;
855 gboolean auto_pay;
856 time64 p_date, d_date;
857 guint curr_count;
858 gboolean scan_date_r;
859 scan_date_r = qof_scan_date (date_posted, &day, &month, &year);
860 DEBUG("Invoice %s is marked to be posted because...", id);
861 DEBUG("qof_scan_date = %d", scan_date_r);
862 if (g_ascii_strcasecmp (type, "INVOICE") == 0)
863 auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_INVOICE, GNC_PREF_AUTO_PAY);
864 else
865 auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_BILL, GNC_PREF_AUTO_PAY);
866 // Do we have any foreign currencies to deal with?
867 foreign_currs = gncInvoiceGetForeignCurrencies (invoice);
868 curr_count = g_hash_table_size (foreign_currs);
869 DEBUG("curr_count = %d",curr_count);
870 // Only auto-post if there's a single currency involved
871 if(curr_count == 0)
872 {
874 (gnc_get_current_root_account (), account_posted);
875 // Check if the currencies match
876 if(gncInvoiceGetCurrency(invoice) == gnc_account_get_currency_or_parent(acc))
877 {
878 qof_scan_date (date_posted, &day, &month, &year);
879 p_date = gnc_dmy2time64 (day, month, year);
880 qof_scan_date (due_date, &day, &month, &year);
881 d_date = gnc_dmy2time64 (day, month, year);
882 gncInvoicePostToAccount (invoice, acc, p_date, d_date,
883 memo_posted,
884 text2bool (accumulatesplits),
885 auto_pay);
886 PWARN("Invoice %s posted",id);
887 invoice_posted = TRUE;
888 g_string_append_printf (info, _("Invoice %s posted.\n"),id);
889 }
890 else // No match! Don't post it.
891 {
892 PWARN("Invoice %s NOT posted because currencies don't match", id);
893 g_string_append_printf (info,_("Invoice %s NOT posted because currencies don't match.\n"), id);
894 }
895 }
896 else
897 {
898 PWARN("Invoice %s NOT posted because it requires currency conversion.",id);
899 g_string_append_printf (info,_("Invoice %s NOT posted because it requires currency conversion.\n"),id);
900 }
901 g_hash_table_unref (foreign_currs);
902 }
903 else
904 {
905 PWARN("Invoice %s is NOT marked for posting",id);
906 }
907
908 // open new bill / invoice in a tab, if requested
909 if (g_ascii_strcasecmp(open_mode, "ALL") == 0
910 || (g_ascii_strcasecmp(open_mode, "NOT_POSTED") == 0
911 && !invoice_posted))
912 {
913 iw = gnc_ui_invoice_edit (parent, invoice);
915 }
916
917 // The next row will be for a new invoice.
918 on_first_row_of_invoice = TRUE;
919 }
920 }
921
922 if (*n_invoices_updated + *n_invoices_created == 0)
923 g_string_append_printf (info, _("Nothing to process.\n"));
924
925 // cleanup
926 g_free (id);
927 g_free (date_opened);
928 g_free (owner_id);
929 g_free (billing_id);
930 g_free (notes);
931 g_free (date);
932 g_free (desc);
933 g_free (action);
934 g_free (account);
935 g_free (quantity);
936 g_free (price);
937 g_free (disc_type);
938 g_free (disc_how);
939 g_free (discount);
940 g_free (taxable);
941 g_free (taxincluded);
942 g_free (tax_table);
943 g_free (date_posted);
944 g_free (due_date);
945 g_free (account_posted);
946 g_free (memo_posted);
947 g_free (accumulatesplits);
948
949 g_string_free (running_id, TRUE);
950}
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.
Definition Account.cpp:3415
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...
Definition gnc-date.cpp:991
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
void gncEntrySetDateGDate(GncEntry *entry, const GDate *date)
Set the date of this entry.
Definition gncEntry.c:504
void gncEntrySetQuantity(GncEntry *entry, gnc_numeric quantity)
Set the internal quantity without any conversion.
Definition gncEntry.c:551
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.
GncPluginPage * gnc_plugin_page_invoice_new(InvoiceWindow *iw)
Create a new "invoice" plugin page, given a pointer to an InvoiceWindow data structure.
GHashTable * gncInvoiceGetForeignCurrencies(const GncInvoice *invoice)
Return an overview of amounts on this invoice that will be posted to accounts in currencies that are ...
void gncBillAddEntry(GncInvoice *bill, GncEntry *entry)
Call this function when adding an entry to a bill instead of an invoice.
Definition gncInvoice.c:719
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.
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
GncOwner * gncOwnerNew(void)
These two functions are mainly for the convenience of scheme code.
Definition gncOwner.c:57
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
STRUCTS.

◆ gnc_bi_import_fix_bis()

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.

Replaces missing or invalid data with defaults:

  • if quantity is not set, default to 1
  • if date_opened is not set or invalid, default to today
  • if date is not set or invalid, default to date_opened
  • if due date is not set or invalid, default to date_posted

Validates the import data; any error causes all rows of the same invoice to be deleted from the import data:

  • id is not set, and there is no previous id
  • owner_id is not set, or customer/vendor does not exist
  • date_posted is not valid
  • account_posted does not exist
  • account posted is not the applicable type, A/P or A/R
  • price is not set
  • account does not exist

Adjustment and validation for header fields is only done for the first row of an invoice, which is assumed to hold the header data for all items of the same invoice. Currency related validation is done in subsqequent processing by gnc_bi_import_create_bis.

Parameters
storeHolds the rows of invoice import data
n_rows_fixedIncreased for every data row that is adjusted in this function
n_rows_ignoredIncreased for every data row that is deleted in this function
infoUpdated with the error messages from this function
typeThe type of the import data, BILL or INVOICE

Definition at line 276 of file dialog-bi-import.c.

278{
279 GtkTreeIter iter, first_row_of_invoice;
280 gboolean valid, row_fixed, on_first_row_of_invoice, ignore_invoice;
281 gchar *id = NULL, *date_opened = NULL, *date_posted = NULL, *due_date = NULL, *account_posted = NULL,
282 *owner_id = NULL, *date = NULL, *account = NULL, *quantity = NULL, *price = NULL;
283 GString *running_id;
284 Account *acc = NULL;
285 guint dummy;
286 gint row = 1, fixed_for_invoice = 0, invoice_line = 0;
287 const gchar* date_format_string = qof_date_format_get_string (qof_date_format_get()); // Get the user set date format string
288
289 DEBUG("date_format_string: %s",date_format_string);
290 // allow the call to this function with only GtkListeStore* specified
291 if (!n_rows_fixed)
292 n_rows_fixed = &dummy;
293 if (!n_rows_ignored)
294 n_rows_ignored = &dummy;
295
296 *n_rows_fixed = 0;
297 *n_rows_ignored = 0;
298
299 // Init control variables
300 running_id = g_string_new("");
301 ignore_invoice = FALSE;
302 on_first_row_of_invoice = TRUE;
303
304 g_string_append_printf (info, _("Validation…\n") );
305
306 // Walk through the list, reading each row.
307 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
308 while (valid)
309 {
310 ++invoice_line;
311 row_fixed = FALSE;
312
313 // If this is a row for a new invoice id, validate header values.
314 if (on_first_row_of_invoice)
315 {
316 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
317 ID, &id,
318 DATE_OPENED, &date_opened,
319 DATE_POSTED, &date_posted,
320 DUE_DATE, &due_date,
321 ACCOUNT_POSTED, &account_posted,
322 OWNER_ID, &owner_id, -1);
323
324 g_string_assign (running_id, id);
325 first_row_of_invoice = iter;
326
327 // Validate the invoice id.
328 if (strlen (id) == 0)
329 {
330 // If there was an earlier valid id, then it replaces an empty id when the next row is read at the end of the loop.
331 // So an empty id error can only happen on the first row of an import file.
332 ignore_invoice = TRUE;
333 g_string_append_printf (info,
334 _("Row %d: no invoice ID in first row of import file.\n"), row);
335 }
336
337 // Validate customer or vendor.
338 if (strlen (owner_id) == 0)
339 {
340 ignore_invoice = TRUE;
341 g_string_append_printf (info,
342 _("Row %d, invoice %s/%u: owner not set.\n"),
343 row, id, invoice_line);
344 }
345 // Verify that customer or vendor exists.
346 if (g_ascii_strcasecmp (type, "BILL") == 0)
347 {
348 if (!gnc_search_vendor_on_id
349 (gnc_get_current_book (), owner_id))
350 {
351 // Vendor not found.
352 ignore_invoice = TRUE;
353 g_string_append_printf (info,
354 _("Row %d, invoice %s/%u: vendor %s does not exist.\n"),
355 row, id, invoice_line, owner_id);
356 }
357 }
358 else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
359 {
360 if (!gnc_search_customer_on_id
361 (gnc_get_current_book (), owner_id))
362 {
363 // Customer not found.
364 ignore_invoice = TRUE;
365 g_string_append_printf (info,
366 _("Row %d, invoice %s/%u: customer %s does not exist.\n"),
367 row, id, invoice_line, owner_id);
368 }
369 }
370
371 if (strlen(date_posted) != 0)
372 {
373 // Validate the date posted and due date.
374 if (!isDateValid(date_posted))
375 {
376 // Invalid date posted in first row of invoice, ignore the invoice
377 ignore_invoice = TRUE;
378 g_string_append_printf (info,
379 _("Row %d, invoice %s/%u: %s is not a valid posting date.\n"),
380 row, id, invoice_line, date_posted);
381
382 // Verify the due date.
383 if (!isDateValid(due_date))
384 {
385 // Invalid due date in first row of invoice, without valid posting date to substitute.
386 g_string_append_printf (info,
387 _("Row %d, invoice %s/%u: %s is not a valid due date.\n"),
388 row, id, invoice_line, due_date);
389 }
390 }
391 else
392 {
393 // Verify the due date.
394 if (!isDateValid(due_date))
395 {
396 // Fix this by using the date posted.
397 gtk_list_store_set (store, &iter, DUE_DATE,
398 date_posted, -1);
399 row_fixed = TRUE;
400 }
401 }
402
403 // Validate account posted.
404 // Account should exists, and should be of type A/R for invoices, A/P for bills.
406 (gnc_get_current_root_account (), account_posted);
407 if (acc == NULL)
408 {
409 ignore_invoice = TRUE;
410 g_string_append_printf (info,
411 _("Row %d, invoice %s/%u: account %s does not exist.\n"),
412 row, id, invoice_line, account_posted);
413 }
414 else
415 {
416 if (g_ascii_strcasecmp (type, "BILL") == 0)
417 {
418
419 if (xaccAccountGetType (acc) != ACCT_TYPE_PAYABLE)
420 {
421 ignore_invoice = TRUE;
422 g_string_append_printf (info,
423 _("Row %d, invoice %s/%u: account %s is not of type Accounts Payable.\n"),
424 row, id, invoice_line, account_posted);
425 }
426 }
427 else if (g_ascii_strcasecmp (type, "INVOICE") == 0)
428 {
429 if (xaccAccountGetType (acc) != ACCT_TYPE_RECEIVABLE)
430 {
431 ignore_invoice = TRUE;
432 g_string_append_printf (info,
433 _("Row %d, invoice %s/%u: account %s is not of type Accounts Receivable.\n"),
434 row, id, invoice_line, account_posted);
435 }
436 }
437 }
438 }
439
440 // Verify the date opened.
441 if(!isDateValid(date_opened))
442 {
443 // Fix this by using the current date.
444 gchar temp[20];
445 GDate date;
446 g_date_clear (&date, 1);
447 gnc_gdate_set_today (&date);
448 g_date_strftime (temp, 20, date_format_string, &date); // Create a user specified date string.
449 gtk_list_store_set (store, &iter, DATE_OPENED,
450 temp, -1);
451 row_fixed = TRUE;
452 }
453 }
454
455 // Validate and fix item data for each row.
456
457 // Get item data.
458 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
459 DATE, &date,
460 ACCOUNT, &account,
461 QUANTITY, &quantity,
462 PRICE, &price, -1);
463
464
465 // Validate the price.
466 if (strlen (price) == 0)
467 {
468 // No valid price, delete the row
469 ignore_invoice = TRUE;
470 g_string_append_printf (info,
471 _("Row %d, invoice %s/%u: price not set.\n"),
472 row, id, invoice_line);
473 }
474
475 // Validate the account
476 acc = gnc_account_lookup_for_register (gnc_get_current_root_account (),
477 account);
478 if (acc == NULL)
479 {
480 ignore_invoice = TRUE;
481 g_string_append_printf (info,
482 _("Row %d, invoice %s/%u: account %s does not exist.\n"),
483 row, id, invoice_line, account);
484 }
485
486 // Fix item data.
487 if (!ignore_invoice)
488 {
489
490 // Verify the quantity.
491 if (strlen (quantity) == 0)
492 {
493 // The quantity is not set, default to 1.
494 gtk_list_store_set (store, &iter, QUANTITY, "1", -1);
495 row_fixed = TRUE;
496 }
497
498 // Verify the item date
499 if(!isDateValid(date))
500 {
501 // Invalid item date, replace with date opened
502 gtk_list_store_set (store, &iter, DATE,
503 date_opened, -1);
504 row_fixed = TRUE;
505 }
506
507 }
508 if (row_fixed) ++fixed_for_invoice;
509
510 // Get the next row and its id.
511 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
512 if (valid) gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &id, -1);
513
514
515 // If the id of the next row is blank, it takes the id of the previous row.
516 if (valid && strlen(id) == 0)
517 {
518 strcpy( id, running_id->str);
519 gtk_list_store_set (store, &iter, ID, id, -1);
520 }
521
522 // If this row was the last row of the invoice...
523 if (!valid || (valid && g_strcmp0 (id, running_id->str) != 0))
524 {
525 // If invoice should be ignored, remove all rows of this invoice.
526 if (ignore_invoice)
527 {
528 iter = first_row_of_invoice;
529 do
530 {
531 (*n_rows_ignored)++;
532 valid = gtk_list_store_remove (store, &iter);
533 if (valid) gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ID, &id, -1);
534 }
535 while (valid && (g_strcmp0 (id, running_id->str) == 0));
536
537 if (running_id->len != 0)
538 {
539 g_string_append_printf (info,
540 _("Error(s) in invoice %s, all rows of this invoice ignored.\n"),
541 running_id->str);
542 }
543 else
544 {
545 g_string_append_printf (info,
546 _("Error(s) in invoice without id, all rows of this invoice ignored.\n"));
547 }
548
549 // Fixes for ignored invoices don't count in the statistics.
550 fixed_for_invoice = 0;
551
552 ignore_invoice = FALSE;
553 }
554
555 on_first_row_of_invoice = TRUE;
556 (*n_rows_fixed) += fixed_for_invoice;
557 fixed_for_invoice = 0;
558 invoice_line = 0;
559
560 g_free (id);
561 g_free (date_opened);
562 g_free (date_posted);
563 g_free (due_date);
564 g_free (account_posted);
565 g_free (owner_id);
566 }
567 else on_first_row_of_invoice = FALSE;
568
569 g_free (date);
570 g_free (account);
571 g_free (quantity);
572 g_free (price);
573
574 row++;
575 }
576
577 // Deallocate strings.
578 g_string_free (running_id, TRUE);
579
580}
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3267
QofDateFormat qof_date_format_get(void)
The qof_date_format_get routine returns the date format that the date printing will use when printing...
Definition gnc-date.cpp:428
void gnc_gdate_set_today(GDate *gd)
Set a GDate to the current day.
const gchar * qof_date_format_get_string(QofDateFormat df)
This function returns a strftime formatting string for printing an all numeric date (e....
Definition gnc-date.cpp:502

◆ gnc_bi_import_read_file()

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.

Opens the csv file and attempts to match each row with the regular expression provided in parser_regexp. This is a regular expression that matches each field of the import row and the user selected field separators (, or ;), optionally with the fields enclosed in quotes.

If the match is successful, the fields of the import row are transferred to a row in the GtkListStore store. If the match is not successful, the row is ignored. Maintains information about number of rows imported, the number of rows ignored, and the actual ignored rows.

Parameters
filenameThe csv filename to read
parser_regexpThe regular expression with which to match the import rows
storeTo store the matched data
max_rowsThe maximum number of rows to import; use 0 for no maximum.
statsReturn information about matched and non-matched rows. Use NULL if the information is not required.

Definition at line 98 of file dialog-bi-import.c.

101{
102 // some statistics
103 bi_import_stats stats_fallback;
104 FILE *f;
105
106 // regexp
107 char *line = NULL;
108 gchar *line_utf8 = NULL;
109 gchar *temp = NULL;
110 GMatchInfo *match_info;
111 GError *err;
112 GRegex *regexpat;
113
114 // model
115 GtkTreeIter iter;
116
117 f = g_fopen (filename, "rt");
118 if (!f)
119 {
120 //gnc_error_dialog (NULL, _("File %s cannot be opened."), filename );
121 return RESULT_OPEN_FAILED;
122 }
123
124 // set up statistics
125 if (!stats)
126 stats = &stats_fallback;
127
128 // compile the regular expression and check for errors
129 err = NULL;
130 regexpat =
131 g_regex_new (parser_regexp, G_REGEX_EXTENDED | G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES, 0, &err);
132 if (err != NULL)
133 {
134 GtkWidget *dialog;
135 gchar *errmsg;
136
137 errmsg = g_strdup_printf (_("Error in regular expression '%s':\n%s"),
138 parser_regexp, err->message);
139 g_error_free (err);
140 err = NULL;
141
142 dialog = gtk_message_dialog_new (NULL,
143 GTK_DIALOG_MODAL,
144 GTK_MESSAGE_ERROR,
145 GTK_BUTTONS_OK, "%s", errmsg);
146 gtk_dialog_run (GTK_DIALOG (dialog));
147 gtk_widget_destroy (dialog);
148 g_free (errmsg);
149 errmsg = 0;
150
151 fclose (f);
152 return RESULT_ERROR_IN_REGEXP;
153 }
154
155 // start the import
156 stats->n_imported = 0;
157 stats->n_ignored = 0;
158 stats->ignored_lines = g_string_new (NULL);
159#define buffer_size 1000
160 line = g_malloc0 (buffer_size);
161 while (!feof (f)
162 && ((max_rows == 0)
163 || (stats->n_imported + stats->n_ignored < max_rows)))
164 {
165 int l;
166 // read one line
167 if (!fgets (line, buffer_size, f))
168 break; // eof
169 // now strip the '\n' from the end of the line
170 l = strlen (line);
171 if ((l > 0) && (line[l - 1] == '\n'))
172 line[l - 1] = 0;
173
174 // if the line doesn't conform to UTF-8, try a default charcter set
175 // conversion based on locale
176 if (g_utf8_validate(line, -1, NULL))
177 line_utf8 = line;
178 else
179 line_utf8 = g_locale_to_utf8 (line, -1, NULL, NULL, NULL);
180
181 // Remove the potential XML-prohibited codepoints from the UTF-8 compliant string
182 gnc_utf8_strip_invalid(line_utf8);
183
184 // parse the line
185 match_info = NULL; // it seems, that in contrast to documentation, match_info is not always set -> g_match_info_free will segfault
186 if (g_regex_match (regexpat, line_utf8, 0, &match_info))
187 {
188 // match found
189 stats->n_imported++;
190
191 // fill in the values
192 gtk_list_store_append (store, &iter);
193 FILL_IN_HELPER ("id", ID); /* FIXME: Should "id" be translated? I don't think so. */
194 FILL_IN_HELPER ("date_opened", DATE_OPENED);
195 FILL_IN_HELPER ("owner_id", OWNER_ID);
196 FILL_IN_HELPER ("billing_id", BILLING_ID);
197 FILL_IN_HELPER ("notes", NOTES);
198
199 FILL_IN_HELPER ("date", DATE);
200 FILL_IN_HELPER ("desc", DESC);
201 FILL_IN_HELPER ("action", ACTION);
202 FILL_IN_HELPER ("account", ACCOUNT);
203 FILL_IN_HELPER ("quantity", QUANTITY);
204 FILL_IN_HELPER ("price", PRICE);
205 FILL_IN_HELPER ("disc_type", DISC_TYPE);
206 FILL_IN_HELPER ("disc_how", DISC_HOW);
207 FILL_IN_HELPER ("discount", DISCOUNT);
208 FILL_IN_HELPER ("taxable", TAXABLE);
209 FILL_IN_HELPER ("taxincluded", TAXINCLUDED);
210 FILL_IN_HELPER ("tax_table", TAX_TABLE);
211
212 FILL_IN_HELPER ("date_posted", DATE_POSTED);
213 FILL_IN_HELPER ("due_date", DUE_DATE);
214 FILL_IN_HELPER ("account_posted", ACCOUNT_POSTED);
215 FILL_IN_HELPER ("memo_posted", MEMO_POSTED);
216 FILL_IN_HELPER ("accu_splits", ACCU_SPLITS);
217 }
218 else
219 {
220 // ignore line
221 stats->n_ignored++;
222 g_string_append (stats->ignored_lines, line_utf8);
223 g_string_append_c (stats->ignored_lines, '\n');
224 }
225
226 g_match_info_free (match_info);
227 if (line_utf8 != line)
228 g_free (line_utf8);
229 }
230 g_free (line);
231 line = 0;
232
233 g_regex_unref (regexpat);
234 regexpat = 0;
235 fclose (f);
236
237 if (stats == &stats_fallback)
238 // stats are not requested -> free the string
239 g_string_free (stats->ignored_lines, TRUE);
240
241 return RESULT_OK;
242}
void gnc_utf8_strip_invalid(gchar *str)
Strip any non-UTF-8 characters from a string.

◆ gnc_customer_import_create_customers()

void gnc_customer_import_create_customers ( GtkListStore *  store,
QofBook book,
guint *  n_customers_created,
guint *  n_customers_updated,
gchar *  type 
)

Definition at line 269 of file dialog-customer-import.c.

270{
271 gboolean valid;
272 GtkTreeIter iter;
273 gchar *id, *company, *name, *addr1, *addr2, *addr3, *addr4, *phone, *fax, *email;
274 gchar *notes, *shipname, *shipaddr1, *shipaddr2, *shipaddr3, *shipaddr4, *shipphone, *shipfax, *shipemail;
275 GncAddress *addr, *shipaddr;
276 guint dummy;
277 GncCustomer *customer;
278 GncVendor *vendor;
279 customer = NULL;
280 vendor = NULL;
281 addr = NULL;
282 shipaddr = NULL;
283 // these arguments are needed
284 g_return_if_fail (store && book);
285 printf("\nTYPE = %s\n", type);
286
287 // allow to call this function without statistics
288 if (!n_customers_created)
289 n_customers_created = &dummy;
290 if (!n_customers_updated)
291 n_customers_updated = &dummy;
292 *n_customers_created = 0;
293 *n_customers_updated = 0;
294
295 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter);
296 while (valid)
297 {
298 // Walk through the list, reading each row
299 gtk_tree_model_get (GTK_TREE_MODEL(store), &iter,
300 CI_ID, &id,
301 CI_COMPANY, &company,
302 CI_NAME, &name,
303 CI_ADDR1, &addr1,
304 CI_ADDR2, &addr2,
305 CI_ADDR3, &addr3,
306 CI_ADDR4, &addr4,
307 CI_PHONE, &phone,
308 CI_FAX, &fax,
309 CI_EMAIL, &email,
310 CI_NOTES, &notes,
311 CI_SHIPNAME, &shipname,
312 CI_SHIPADDR1, &shipaddr1,
313 CI_SHIPADDR2, &shipaddr2,
314 CI_SHIPADDR3, &shipaddr3,
315 CI_SHIPADDR4, &shipaddr4,
316 CI_SHIPPHONE, &shipphone,
317 CI_SHIPFAX, &shipfax,
318 CI_SHIPEMAIL, &shipemail,
319 -1);
320
321 // Set the customer id if one has not been chosen
322 if (strlen (id) == 0)
323 {
324 if (g_ascii_strcasecmp (type, "CUSTOMER") == 0) id = gncCustomerNextID (book);
325 else if (g_ascii_strcasecmp (type, "VENDOR") == 0)id = gncVendorNextID (book);
326 //printf("ASSIGNED ID = %s\n",id);
327 }
328
329 // Now save it off after checking if a vend/cust number doesn't already exist
330 {
331 if (g_ascii_strcasecmp (type, "CUSTOMER") == 0)
332 {
333 customer = gnc_search_customer_on_id (book, id);
334 if (!customer)
335 {
336 customer = gncCustomerCreate( book );
337 gncCustomerSetCurrency( customer, gnc_default_currency() );
338 (*n_customers_created)++;
339 }
340 else (*n_customers_updated)++;
341 }
342 else if (g_ascii_strcasecmp (type, "VENDOR") == 0)
343 {
344 vendor = gnc_search_vendor_on_id (book, id);
345 if ( !vendor)
346 {
347 vendor = gncVendorCreate( book );
348 gncVendorSetCurrency( vendor, gnc_default_currency() );
349 (*n_customers_created)++;
350 }
351 else (*n_customers_updated)++;
352 }
353
354 if (g_ascii_strcasecmp (type, "CUSTOMER") == 0)
355 {
356 gncCustomerBeginEdit (customer);
357 gncCustomerSetID (customer, id);
358 gncCustomerSetName (customer, company);
359 gncCustomerSetNotes (customer, notes);
360 addr = gncCustomerGetAddr (customer);
361 shipaddr = gncCustomerGetShipAddr (customer);
362 }
363 else if (g_ascii_strcasecmp (type, "VENDOR") == 0)
364 {
365 gncVendorBeginEdit (vendor);
366 gncVendorSetID (vendor, id);
367 gncVendorSetName (vendor, company);
368 gncVendorSetNotes (vendor, notes);
369 addr = gncVendorGetAddr (vendor);
370 }
371 gncAddressSetName (addr, name);
372 gncAddressSetAddr1 (addr, addr1);
373 gncAddressSetAddr2 (addr, addr2);
374 gncAddressSetAddr3 (addr, addr3);
375 gncAddressSetAddr4 (addr, addr4);
376 gncAddressSetPhone (addr, phone);
377 gncAddressSetFax (addr, fax);
378 gncAddressSetEmail (addr, email);
379 if (g_ascii_strcasecmp (type, "CUSTOMER") == 0)
380 {
381 gncAddressSetName (shipaddr, shipname);
382 gncAddressSetAddr1 (shipaddr, shipaddr1);
383 gncAddressSetAddr2 (shipaddr, shipaddr2);
384 gncAddressSetAddr3 (shipaddr, shipaddr3);
385 gncAddressSetAddr4 (shipaddr, shipaddr4);
386 gncAddressSetPhone (shipaddr, shipphone);
387 gncAddressSetFax (shipaddr, shipfax);
388 gncAddressSetEmail (shipaddr, shipemail);
389 gncCustomerSetActive (customer, TRUE);
390 gncCustomerCommitEdit (customer);
391 }
392 else if (g_ascii_strcasecmp (type, "VENDOR") == 0)
393 {
394 gncVendorSetActive (vendor, TRUE);
395 gncVendorCommitEdit (vendor);
396 }
397 //printf("TYPE %s created with ID = %s.\n", type, id); // DEBUG
398 }
399
400 g_free (id);
401 g_free (company);
402 g_free (name);
403 g_free (addr1);
404 g_free (addr2);
405 g_free (addr3);
406 g_free (addr4);
407 g_free (phone);
408 g_free (fax);
409 g_free (email);
410 g_free (notes);
411 g_free (shipname);
412 g_free (shipaddr1);
413 g_free (shipaddr2);
414 g_free (shipaddr3);
415 g_free (shipaddr4);
416 g_free (shipphone);
417 g_free (shipfax);
418 g_free (shipemail);
419 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
420 }
421}
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,...

◆ gnc_customer_import_fix_customers()

void gnc_customer_import_fix_customers ( GtkListStore *  store,
guint *  fixed,
guint *  deleted,
gchar *  type 
)

Definition at line 207 of file dialog-customer-import.c.

208{
209 GtkTreeIter iter;
210 gboolean valid;
211 gchar *company, *name, *addr1, *addr2, *addr3, *addr4;
212 guint dummy;
213
214 // allow the call to this function with only GtkListeStore* specified
215 if (!fixed)
216 fixed = &dummy;
217 if (!deleted)
218 deleted = &dummy;
219
220 *fixed = 0;
221 *deleted = 0;
222
223 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter);
224 while (valid)
225 {
226 // Walk through the list, reading each row
227 gtk_tree_model_get (GTK_TREE_MODEL(store), &iter,
228 CI_COMPANY, &company,
229 CI_NAME, &name,
230 CI_ADDR1, &addr1,
231 CI_ADDR2, &addr2,
232 CI_ADDR3, &addr3,
233 CI_ADDR4, &addr4,
234 -1);
235
236 // Company name is mandatory.
237 // If not provided, default the company name to the value of the field name.
238 if (strlen(company) == 0)
239 {
240 //But if the field name is also blank, then delete the row.
241 if (strlen(name) == 0)
242 {
243 // no fix possible -> delete row
244 valid = gtk_list_store_remove (store, &iter);
245 (*deleted)++;
246 continue;
247 }
248 else
249 {
250 // fix possible -> copy name to company
251 gtk_list_store_set (store, &iter, CI_COMPANY, name, -1);
252 (*fixed)++;
253 }
254 }
255
256
257 g_free (company);
258 g_free (name);
259 g_free (addr1);
260 g_free (addr2);
261 g_free (addr3);
262 g_free (addr4);
263
264 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
265 }
266}

◆ gnc_customer_import_read_file()

customer_import_result gnc_customer_import_read_file ( const gchar *  filename,
const gchar *  parser_regexp,
GtkListStore *  store,
guint  max_rows,
customer_import_stats *  stats 
)

Definition at line 68 of file dialog-customer-import.c.

69{
70 // some statistics
71 customer_import_stats stats_fallback;
72 FILE *f;
73
74 // regexp
75 char *line;
76 gchar *line_utf8, *temp;
77 GMatchInfo *match_info;
78 GError *err;
79 GRegex *regexpat;
80
81 // model
82 GtkTreeIter iter;
83
84 f = g_fopen( filename, "rt" );
85 if (!f)
86 {
87 //gnc_error_dialog (NULL, _("File %s cannot be opened."), filename );
88 return CI_RESULT_OPEN_FAILED;
89 }
90
91 // set up statistics
92 if (!stats)
93 stats = &stats_fallback;
94
95 // compile the regular expression and check for errors
96 err = NULL;
97 regexpat = g_regex_new (parser_regexp, G_REGEX_EXTENDED | G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES, 0, &err);
98 if (err != NULL)
99 {
100 GtkWidget *dialog;
101 gchar *errmsg;
102
103 errmsg = g_strdup_printf (_("Error in regular expression '%s':\n%s"),
104 parser_regexp, err->message);
105 g_error_free (err);
106 err = NULL;
107
108 dialog = gtk_message_dialog_new (NULL,
109 GTK_DIALOG_MODAL,
110 GTK_MESSAGE_ERROR,
111 GTK_BUTTONS_OK,
112 "%s", errmsg);
113 gtk_dialog_run (GTK_DIALOG (dialog));
114 gtk_widget_destroy(dialog);
115 g_free (errmsg);
116 errmsg = 0;
117
118 fclose (f);
119 return CI_RESULT_ERROR_IN_REGEXP;
120 }
121
122 // start the import
123 stats->n_imported = 0;
124 stats->n_ignored = 0;
125 stats->ignored_lines = g_string_new (NULL);
126#define buffer_size 1000
127 line = g_malloc0 (buffer_size);
128 while (!feof (f) && ((max_rows == 0) || (stats->n_imported + stats->n_ignored < max_rows)))
129 {
130 int l;
131 // read one line
132 if (!fgets (line, buffer_size, f))
133 break; // eof
134 // now strip the '\n' from the end of the line
135 l = strlen (line);
136 if ((l > 0) && (line[l - 1] == '\n'))
137 line[l - 1] = 0;
138
139 // if the line doesn't conform to UTF-8, try a default charcter set
140 // conversion based on locale
141 if (g_utf8_validate(line, -1, NULL))
142 line_utf8 = line;
143 else
144 line_utf8 = g_locale_to_utf8 (line, -1, NULL, NULL, NULL);
145
146 // Remove the potential XML-prohibited codepoints from the UTF-8 compliant string
147 gnc_utf8_strip_invalid(line_utf8);
148
149 // parse the line
150 match_info = NULL; // it seems, that in contrast to documentation, match_info is not always set -> g_match_info_free will segfault
151 if (g_regex_match (regexpat, line_utf8, 0, &match_info))
152 {
153 // match found
154 stats->n_imported++;
155
156 // fill in the values
157 gtk_list_store_append (store, &iter);
158 FILL_IN_HELPER ("id", CI_ID);
159 FILL_IN_HELPER ("company", CI_COMPANY);
160 FILL_IN_HELPER ("name", CI_NAME);
161 FILL_IN_HELPER ("addr1", CI_ADDR1);
162 FILL_IN_HELPER ("addr2", CI_ADDR2);
163 FILL_IN_HELPER ("addr3", CI_ADDR3);
164 FILL_IN_HELPER ("addr4", CI_ADDR4);
165 FILL_IN_HELPER ("phone", CI_PHONE);
166 FILL_IN_HELPER ("fax", CI_FAX);
167 FILL_IN_HELPER ("email", CI_EMAIL);
168 FILL_IN_HELPER ("notes", CI_NOTES);
169 FILL_IN_HELPER ("shipname", CI_SHIPNAME);
170 FILL_IN_HELPER ("shipaddr1", CI_SHIPADDR1);
171 FILL_IN_HELPER ("shipaddr2", CI_SHIPADDR2);
172 FILL_IN_HELPER ("shipaddr3", CI_SHIPADDR3);
173 FILL_IN_HELPER ("shipaddr4", CI_SHIPADDR4);
174 FILL_IN_HELPER ("shipphone", CI_SHIPPHONE);
175 FILL_IN_HELPER ("shipfax", CI_SHIPFAX);
176 FILL_IN_HELPER ("shipemail", CI_SHIPEMAIL);
177 }
178 else
179 {
180 // ignore line
181 stats->n_ignored++;
182 g_string_append (stats->ignored_lines, line_utf8);
183 g_string_append_c (stats->ignored_lines, '\n');
184 }
185
186 g_match_info_free (match_info);
187 if (line_utf8 != line)
188 g_free (line_utf8);
189 }
190 g_free (line);
191 line = 0;
192
193 g_regex_unref (regexpat);
194 regexpat = 0;
195 fclose (f);
196
197 if (stats == &stats_fallback)
198 // stats are not requested -> free the string
199 g_string_free (stats->ignored_lines, TRUE);
200
201 return CI_RESULT_OK;
202}

◆ gnc_plugin_bi_import_create_plugin()

void gnc_plugin_bi_import_create_plugin ( void  )

Create a new GncPluginbi_import object and register it.

Definition at line 120 of file gnc-plugin-bi-import.c.

121{
122 GncPlugin *plugin = gnc_plugin_bi_import_new ();
123
125}
void gnc_plugin_manager_add_plugin(GncPluginManager *manager, GncPlugin *plugin)
Add a plugin to the list maintained by the plugin manager.
GncPluginManager * gnc_plugin_manager_get(void)
Retrieve a pointer to the plugin manager.
GncPlugin * gnc_plugin_bi_import_new(void)

◆ gnc_plugin_bi_import_new()

GncPlugin * gnc_plugin_bi_import_new ( void  )
Returns
A new GncPluginbi_import object

Definition at line 80 of file gnc-plugin-bi-import.c.

81{
82 return GNC_PLUGIN (g_object_new (GNC_TYPE_PLUGIN_BI_IMPORT, (gchar*) NULL));
83}

◆ gnc_plugin_bi_import_showGUI()

BillImportGui * gnc_plugin_bi_import_showGUI ( GtkWindow *  parent)

File chooser.

Definition at line 82 of file dialog-bi-import-gui.c.

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}

◆ gnc_plugin_customer_import_create_plugin()

void gnc_plugin_customer_import_create_plugin ( void  )

Create a new GncPlugincustomer_import object and register it.

Definition at line 118 of file gnc-plugin-customer-import.c.

119{
120 GncPlugin *plugin = gnc_plugin_customer_import_new ();
121
123}
GncPlugin * gnc_plugin_customer_import_new(void)

◆ gnc_plugin_customer_import_new()

GncPlugin * gnc_plugin_customer_import_new ( void  )
Returns
A new GncPlugincustomer_import object

Definition at line 78 of file gnc-plugin-customer-import.c.

79{
80 return GNC_PLUGIN (g_object_new (GNC_TYPE_PLUGIN_CUSTOMER_IMPORT, (gchar*) NULL));
81}

◆ gnc_plugin_customer_import_showGUI()

CustomerImportGui * gnc_plugin_customer_import_showGUI ( GtkWindow *  parent)

File chooser.

Definition at line 72 of file dialog-customer-import-gui.c.

73{
74 CustomerImportGui *gui;
75 //gktbuilderXML *xml;
76 GtkBuilder *builder;
77 GList *glist;
78 GtkCellRenderer *renderer;
79 GtkTreeViewColumn *column;
80
81 // if window exists already, activate it
82 glist = gnc_find_gui_components ("dialog-customer-import-gui", NULL, NULL);
83 if (glist)
84 {
85 // window found
86 gui = g_list_nth_data (glist, 0);
87 g_list_free (glist);
88 gtk_window_present (GTK_WINDOW(gui->dialog));
89 return gui;
90 }
91
92 // create new window
93 gui = g_new0 (CustomerImportGui, 1);
94
95 builder = gtk_builder_new();
96 gnc_builder_add_from_file (builder, "dialog-customer-import-gui.glade", "customer_import_dialog");
97 gui->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "customer_import_dialog"));
98 gui->tree_view = GTK_WIDGET(gtk_builder_get_object (builder, "treeview1"));
99 gui->entryFilename = GTK_WIDGET(gtk_builder_get_object (builder, "entryFilename"));
100 gui->type = "CUSTOMER"; // Set a default type to import
101
102 // Set the name for this dialog so it can be easily manipulated with css
103 gtk_widget_set_name (GTK_WIDGET(gui->dialog), "gnc-id-customer-import");
104 gnc_widget_style_context_add_class (GTK_WIDGET(gui->dialog), "gnc-class-imports");
105
106 gtk_window_set_transient_for (GTK_WINDOW (gui->dialog), parent);
107
108 gui->regexp = g_string_new ( "^(\\x{FEFF})?(?<id>[^;]*);(?<company>[^;]*);(?<name>[^;]*);(?<addr1>[^;]*);(?<addr2>[^;]*);(?<addr3>[^;]*);(?<addr4>[^;]*);(?<phone>[^;]*);(?<fax>[^;]*);(?<email>[^;]*);(?<notes>[^;]*);(?<shipname>[^;]*);(?<shipaddr1>[^;]*);(?<shipaddr2>[^;]*);(?<shipaddr3>[^;]*);(?<shipaddr4>[^;]*);(?<shipphone>[^;]*);(?<shipfax>[^;]*);(?<shipemail>[^;]*)$");
109 gui->book = gnc_get_current_book();
110
111 // create model and bind to view
112 gui->store = gtk_list_store_new (CI_N_COLUMNS,
113 G_TYPE_STRING, G_TYPE_STRING,
114 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
115 G_TYPE_STRING,
116 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
117 gtk_tree_view_set_model( GTK_TREE_VIEW(gui->tree_view), GTK_TREE_MODEL(gui->store) );
118#define CREATE_COLUMN(description,column_id) \
119 renderer = gtk_cell_renderer_text_new (); \
120 column = gtk_tree_view_column_new_with_attributes (description, renderer, "text", column_id, NULL); \
121 gtk_tree_view_column_set_resizable (column, TRUE); \
122 gtk_tree_view_append_column (GTK_TREE_VIEW (gui->tree_view), column);
123 CREATE_COLUMN (_("ID"), CI_ID);
124 CREATE_COLUMN (_("Company"), CI_COMPANY);
125 CREATE_COLUMN (_("Name"), CI_NAME);
126 CREATE_COLUMN (_("Address 1"), CI_ADDR1);
127 CREATE_COLUMN (_("Address 2"), CI_ADDR2);
128 CREATE_COLUMN (_("Address 3"), CI_ADDR3);
129 CREATE_COLUMN (_("Address 4"), CI_ADDR4);
130 CREATE_COLUMN (_("Phone"), CI_PHONE);
131 CREATE_COLUMN (_("Fax"), CI_FAX);
132 CREATE_COLUMN (_("Email"), CI_EMAIL);
133 CREATE_COLUMN (_("Notes"), CI_NOTES);
134 CREATE_COLUMN (_("Shipping Name"), CI_SHIPNAME);
135 CREATE_COLUMN (_("Shipping Address 1"), CI_SHIPADDR1);
136 CREATE_COLUMN (_("Shipping Address 2"), CI_SHIPADDR2);
137 CREATE_COLUMN (_("Shipping Address 3"), CI_SHIPADDR3);
138 CREATE_COLUMN (_("Shipping Address 4"), CI_SHIPADDR4);
139 CREATE_COLUMN (_("Shipping Phone"), CI_SHIPPHONE);
140 CREATE_COLUMN (_("Shipping Fax"), CI_SHIPFAX);
141 CREATE_COLUMN (_("Shipping Email"), CI_SHIPEMAIL);
142
143 gui->component_id = gnc_register_gui_component ("dialog-customer-import-gui",
144 NULL,
145 gnc_customer_import_gui_close_handler,
146 gui);
147
148 /* Setup signals */
149 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, gui);
150 gtk_widget_show_all ( gui->dialog );
151 g_object_unref (G_OBJECT (builder));
152 return gui;
153}

◆ gnc_plugin_example_new()

GncPlugin * gnc_plugin_example_new ( void  )
Returns
A new GncPluginexample object

Definition at line 66 of file gnc-plugin.example.c.

67{
68 return GNC_PLUGIN (g_object_new (GNC_TYPE_PLUGIN_EXAMPLE, (gchar*) NULL));
69}