GnuCash 038f90a+
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 606 of file dialog-bi-import.c.

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