/** * Parse XML category node and fill a gnucash_category with results. * Add category to the global category list. * * \param categ_node XML category node to parse. */ void recuperation_donnees_gnucash_categorie ( xmlNodePtr categ_node ) { struct gnucash_category * categ; categ = calloc ( 1, sizeof ( struct gnucash_category )); /* Find name, could be tricky if there is a parent. */ categ -> name = child_content ( categ_node, "name" ); if ( child_content ( categ_node, "parent" ) ) { gchar * parent_guid = child_content ( categ_node, "parent" ); GSList * liste_tmp = gnucash_categories; while ( liste_tmp ) { struct gnucash_category * iter = liste_tmp -> data; if ( !strcmp ( iter -> guid, parent_guid ) ) { categ -> name = g_strconcat ( iter -> name, " : ", categ -> name, NULL ); break; } liste_tmp = liste_tmp -> next; } } categ -> guid = child_content ( categ_node, "id" ); /* Find if this is an expense or income category. */ if ( !strcmp ( child_content ( categ_node, "type" ), "INCOME" ) ) { categ -> type = GNUCASH_CATEGORY_INCOME; } else { categ -> type = GNUCASH_CATEGORY_EXPENSE; } gnucash_categories = g_slist_append ( gnucash_categories, categ ); }
/** * Parse XML account node and fill a struct_compte_importation with * results. Add account to the global accounts list * gnucash_accounts. * * \param compte_node XML account node to parse. */ void recuperation_donnees_gnucash_compte ( xmlNodePtr compte_node ) { struct struct_compte_importation *compte; gchar * type = child_content ( compte_node, "type" ); gsb_real null_real = { 0, 0 }; compte = calloc ( 1, sizeof ( struct struct_compte_importation )); /* Gnucash import */ compte -> origine = my_strdup ( "Gnucash" ); if ( !strcmp(type, "BANK") || !strcmp(type, "CREDIT") ) { compte -> type_de_compte = 0; /* Bank */ } else if ( !strcmp(type, "CASH") || !strcmp(type, "CURRENCY") ) { compte -> type_de_compte = 1; /* Currency */ } else if ( !strcmp(type, "ASSET") || !strcmp(type, "STOCK") || !strcmp(type, "MUTUAL") ) { compte -> type_de_compte = 0; /* Asset */ } else if ( !strcmp(type, "LIABILITY") ) { compte -> type_de_compte = 0; /* Liability */ } compte -> nom_de_compte = child_content ( compte_node, "name" ); compte -> filename = gnucash_filename; compte -> solde = null_real; compte -> devise = get_currency ( get_child(compte_node, "commodity") ); compte -> guid = child_content ( compte_node, "id" ); compte -> operations_importees = NULL; compte -> nom_de_compte = unique_imported_name ( compte -> nom_de_compte ); gsb_import_register_account ( compte ); gnucash_accounts = g_slist_append ( gnucash_accounts, compte ); }
/** * Parse XML book nodes from a gnucash file. * * Main role of this function is to iterate over XML nodes of the file * and determine which account nodes are category nodes and which are * real accounts, as in Gnucash, accounts and categories are mixed. * * \param book_node Pointer to current XML node. */ void recuperation_donnees_gnucash_book ( xmlNodePtr book_node ) { xmlNodePtr child_node; child_node = book_node -> children; while ( child_node ) { /* Books are subdivisions of gnucash files */ if ( node_strcmp ( child_node, "book" ) ) { recuperation_donnees_gnucash_book ( child_node ); } if ( node_strcmp(child_node, "account") ) { gchar * type = child_content ( child_node, "type"); if ( strcmp(type, "INCOME") && strcmp(type, "EXPENSE") && strcmp(type, "EXPENSES") && strcmp(type, "EQUITY") ) { recuperation_donnees_gnucash_compte ( child_node ); } else { recuperation_donnees_gnucash_categorie ( child_node ); } } if ( node_strcmp(child_node, "transaction") ) { recuperation_donnees_gnucash_transaction ( child_node ); } child_node = child_node -> next; } }
/** * Utility functions that returns currency value of a currency node. * * \param currency_node XML node to parse. * * \return string Representation of currency */ gchar * get_currency ( xmlNodePtr currency_node ) { return child_content ( currency_node, "id" ); }
/** * Parse XML transaction node and fill a ImportTransaction with results. * * \param transaction_node XML transaction node to parse. */ void recuperation_donnees_gnucash_transaction ( xmlNodePtr transaction_node ) { struct ImportTransaction * transaction; struct ImportAccount * account = NULL; struct gnucash_split * split; gchar * date_string, *space, *tiers; GDate * date; xmlNodePtr splits, split_node, date_node; GSList * split_list = NULL; GsbReal total = { 0 , 0 }; /* Transaction amount, category, account, etc.. */ splits = get_child ( transaction_node, "splits" ); split_node = splits -> children; while ( split_node ) { struct ImportAccount * split_account = NULL; struct gnucash_category * categ = NULL; gint p_r = OPERATION_NORMALE; GsbReal amount; /** * Gnucash transactions are in fact "splits", much like grisbi's * splits of transactions. We need to parse all splits and * see whether they are transfers to real accounts or transfers * to category accounts. In that case, we only create one * transactions. The other is discarded as grisbi is not a * double part financial engine. */ if ( node_strcmp ( split_node, "split" ) ) { gchar * account_name = NULL, * categ_name = NULL; split_account = find_imported_account_by_uid ( child_content ( split_node, "account" ) ); categ = find_imported_categ_by_uid ( child_content ( split_node, "account" ) ); amount = gnucash_value ( child_content(split_node, "value") ); if ( categ ) categ_name = categ -> name; if ( split_account ) { /* All of this stuff is here since we are dealing with the account split, not the category one */ account_name = split_account -> nom_de_compte; total = gsb_real_add ( total, amount ); if ( strcmp(child_content(split_node, "reconciled-state"), "n") ) p_r = OPERATION_RAPPROCHEE; } split = find_split ( split_list, amount, split_account, categ ); if ( split ) { update_split ( split, amount, account_name, categ_name ); } else { split = new_split ( amount, account_name, categ_name ); split_list = g_slist_append ( split_list, split ); split -> notes = child_content(split_node, "memo"); } if ( p_r != OPERATION_NORMALE ) split -> p_r = p_r; } split_node = split_node -> next; } if ( ! split_list ) return; /* Transaction date */ date_node = get_child ( transaction_node, "date-posted" ); date_string = child_content (date_node, "date"); space = strchr ( date_string, ' ' ); if ( space ) *space = 0; date = g_date_new (); g_date_set_parse ( date, date_string ); if ( !g_date_valid ( date )) fprintf ( stderr, "grisbi: Can't parse date %s\n", date_string ); /* Tiers */ tiers = child_content ( transaction_node, "description" ); /* Create transaction */ split = split_list -> data; transaction = new_transaction_from_split ( split, tiers, date ); transaction -> operation_ventilee = 0; transaction -> ope_de_ventilation = 0; account = find_imported_account_by_name ( split -> account ); if ( account ) account -> operations_importees = g_slist_append ( account -> operations_importees, transaction ); /** Splits of transactions are handled the same way, we process them if we find more than one split in transaction node. */ if ( g_slist_length ( split_list ) > 1 ) { transaction -> operation_ventilee = 1; transaction -> montant = total; while ( split_list ) { split = split_list -> data; account = NULL; transaction = new_transaction_from_split ( split, tiers, date ); transaction -> ope_de_ventilation = 1; account = find_imported_account_by_name ( split -> account ); if ( account ) account -> operations_importees = g_slist_append ( account -> operations_importees, transaction ); split_list = split_list -> next; } } }