static void test_load_file(const char *filename) { QofSession *session; QofBook *book; Account *root; gboolean ignore_lock; gchar *logdomain = "GConf"; guint loglevel = G_LOG_LEVEL_WARNING; TestErrorStruct check = { loglevel, logdomain, NULL }; g_log_set_handler (logdomain, loglevel, (GLogFunc)test_checked_handler, &check); session = qof_session_new(); remove_locks(filename); ignore_lock = (safe_strcmp(g_getenv("SRCDIR"), ".") != 0); qof_session_begin(session, filename, ignore_lock, FALSE, TRUE); qof_session_load(session, NULL); book = qof_session_get_book (session); root = gnc_book_get_root_account(book); do_test (gnc_account_get_book (root) == book, "book and root account don't match"); do_test_args(qof_session_get_error(session) == ERR_BACKEND_NO_ERR, "session load xml2", __FILE__, __LINE__, "qof error=%d for file [%s]", qof_session_get_error(session), filename); /* Uncomment the line below to generate corrected files */ qof_session_save( session, NULL ); qof_session_end(session); }
TEST_F(ImapTest, CreateImap) { GncImportMatchMap *imap = gnc_account_imap_create_imap (t_bank_account); EXPECT_NE(nullptr, imap); EXPECT_EQ(t_bank_account, imap->acc); EXPECT_EQ(gnc_account_get_book(t_bank_account), imap->book); g_free(imap); }
static void save_templates(GtkWidget *parent, Account *gnc_acc, GList *templates, gboolean dont_ask) { g_return_if_fail(gnc_acc); if (dont_ask || gnc_verify_dialog( parent, FALSE, "%s", _("You have changed the list of online transfer templates, " "but you cancelled the transfer dialog. " "Do you nevertheless want to store the changes?"))) { gnc_ab_set_book_template_list(gnc_account_get_book(gnc_acc), templates); } }
/** Create a transaction and splits from a pair of trans and split property objects. * Note: this function assumes all properties have been verified * to be valid and the required properties are available. * @param parsed_line The current line being parsed * @return On success, a shared pointer to a DraftTransaction object; on failure a nullptr */ std::shared_ptr<DraftTransaction> GncTxImport::trans_properties_to_trans (std::vector<parse_line_t>::iterator& parsed_line) { auto created_trans = false; std::string error_message; std::shared_ptr<GncPreTrans> trans_props; std::shared_ptr<GncPreSplit> split_props; std::tie(std::ignore, error_message, trans_props, split_props, std::ignore) = *parsed_line; auto account = split_props->get_account(); QofBook* book = gnc_account_get_book (account); gnc_commodity* currency = xaccAccountGetCommodity (account); auto trans = trans_props->create_trans (book, currency); if (trans) { /* We're about to continue with a new transaction * Time to do some closing actions on the previous one */ if (m_current_draft && m_current_draft->void_reason) { /* The import data specifies this transaction was voided. * So void the created transaction as well. * Attention: this assumes the imported transaction was balanced. * If not, this will cause an imbalance split to be added automatically! */ xaccTransCommitEdit (m_current_draft->trans); xaccTransVoid (m_current_draft->trans, m_current_draft->void_reason->c_str()); } m_current_draft = std::make_shared<DraftTransaction>(trans); m_current_draft->void_reason = trans_props->get_void_reason(); created_trans = true; } else if (m_settings.m_multi_split) // in multi_split mode create_trans will return a nullptr for all but the first split trans = m_current_draft->trans; else // in non-multi-split mode each line should be a transaction, so not having one here is an error throw std::invalid_argument ("Failed to create transaction from selected columns."); if (!trans) return nullptr; split_props->create_split(trans); /* Only return the draft transaction if we really created a new one * The return value will be added to a list for further processing, * we want each transaction to appear only once in that list. */ return created_trans ? m_current_draft : nullptr; }
void gnc_book_set_template_root (QofBook *book, Account *templateRoot) { QofCollection *col; if (!book) return; if (templateRoot && gnc_account_get_book(templateRoot) != book) { g_critical("cannot mix and match books freely!"); return; } col = qof_book_get_collection (book, GNC_ID_SXTG); gnc_collection_set_template_root (col, templateRoot); }
Account *gnc_ofx_kvp_get_assoc_account(const Account* investment_account) { kvp_frame * acc_frame; kvp_value * kvp_val; Account *result = NULL; g_assert(investment_account); acc_frame = xaccAccountGetSlots(investment_account); kvp_val = kvp_frame_get_slot(acc_frame, KEY_ASSOC_INCOME_ACCOUNT); if (kvp_val != NULL) { result = xaccAccountLookup(kvp_value_get_guid(kvp_val), gnc_account_get_book(investment_account)); } return result; }
static void refresh_details_page (StockSplitInfo *info) { GNCPrintAmountInfo print_info; gnc_commodity *commodity, *currency; Account *account; QofBook *book; GNCPriceDB *db; GList *prices; account = info->acct; g_return_if_fail (account != NULL); print_info = gnc_account_print_info (account, FALSE); gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (info->distribution_edit), print_info); gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (info->distribution_edit), xaccAccountGetCommoditySCU (account)); commodity = xaccAccountGetCommodity (account); book = gnc_account_get_book (account); db = gnc_pricedb_get_db(book); prices = gnc_pricedb_lookup_latest_any_currency(db, commodity); if (prices) { /* Use the first existing price */ if (gnc_commodity_equiv (commodity, gnc_price_get_currency(prices->data))) currency = gnc_price_get_commodity(prices->data); else currency = gnc_price_get_currency(prices->data); } else { /* Take a wild guess. */ currency = gnc_default_currency (); } gnc_price_list_destroy(prices); gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT (info->price_currency_edit), currency); }
void ViewletModel::rightVGenerate(::Account *selectedAccount) { ::QofBook *book = gnc_account_get_book(selectedAccount); ::Account *rootAccount = gnc_book_get_root_account(book); GList *accountsGList = gnc_account_get_descendants(rootAccount); AccountQList accountsList = accountFromGList(accountsGList); int numOfAccounts = accountsList.count(); qDebug()<<"Total num of accounts: "<<numOfAccounts; AccountQList expenseAccountsList; for(int i = 0; i < numOfAccounts; i++) { if(xaccAccountGetType(accountsList.at(i)) == 8) { expenseAccountsList.append(accountsList.at(i)); } } SplitQList splitsList = buildSplitListDateSort(expenseAccountsList); buildMiniJournalStruct(splitsList); }
Account * xaccScrubUtilityGetOrMakeAccount (Account *root, gnc_commodity * currency, const char *accname, GNCAccountType acctype, gboolean placeholder) { Account * acc; g_return_val_if_fail (root, NULL); /* build the account name */ if (!currency) { PERR ("No currency specified!"); return NULL; } /* See if we've got one of these going already ... */ acc = gnc_account_lookup_by_name(root, accname); if (acc == NULL) { /* Guess not. We'll have to build one. */ acc = xaccMallocAccount(gnc_account_get_book (root)); xaccAccountBeginEdit (acc); xaccAccountSetName (acc, accname); xaccAccountSetCommodity (acc, currency); xaccAccountSetType (acc, acctype); xaccAccountSetPlaceholder (acc, placeholder); /* Hang the account off the root. */ gnc_account_append_child (root, acc); xaccAccountCommitEdit (acc); } return acc; }
/** Creates a list of transactions from parsed data. Transactions that * could be created from rows are placed in parse_data->transactions; * rows that fail are placed in parse_data->error_lines. (Note: there * is no way for this function to "fail," i.e. it only returns 0, so * it may be changed to a void function in the future.) * @param parse_data Data that is being parsed * @param account Account with which transactions are created * @param redo_errors TRUE to convert only error data, FALSE for all data * @return 0 on success, 1 on failure */ int gnc_csv_parse_to_trans (GncCsvParseData* parse_data, Account* account, gboolean redo_errors) { gboolean hasBalanceColumn; int i, j, max_cols = 0; GArray* column_types = parse_data->column_types; GList *error_lines = NULL, *begin_error_lines = NULL; /* last_transaction points to the last element in * parse_data->transactions, or NULL if it's empty. */ GList* last_transaction = NULL; /* Free parse_data->error_lines and parse_data->transactions if they * already exist. */ if (redo_errors) /* If we're redoing errors, we save freeing until the end. */ { begin_error_lines = error_lines = parse_data->error_lines; } else { if (parse_data->error_lines != NULL) { g_list_free(parse_data->error_lines); } if (parse_data->transactions != NULL) { g_list_free (parse_data->transactions); } } parse_data->error_lines = NULL; if (redo_errors) /* If we're looking only at error data ... */ { if (parse_data->transactions == NULL) { last_transaction = NULL; } else { /* Move last_transaction to the end. */ last_transaction = parse_data->transactions; while (g_list_next (last_transaction) != NULL) { last_transaction = g_list_next (last_transaction); } } /* ... we use only the lines in error_lines. */ if (error_lines == NULL) i = parse_data->orig_lines->len; /* Don't go into the for loop. */ else i = GPOINTER_TO_INT(error_lines->data); } else /* Otherwise, we look at all the data. */ { /* The following while-loop effectively behaves like the following for-loop: * for(i = 0; i < parse_data->orig_lines->len; i++). */ i = parse_data->start_row; last_transaction = NULL; } /* set parse_data->end_row to number of lines */ if (parse_data->end_row > parse_data->orig_lines->len) parse_data->end_row = parse_data->orig_lines->len; while (i < parse_data->end_row) { GPtrArray* line = parse_data->orig_lines->pdata[i]; /* This flag is TRUE if there are any errors in this row. */ gboolean errors = FALSE; gchar* error_message = NULL; TransPropertyList* list = trans_property_list_new (account, parse_data->date_format, parse_data->currency_format); GncCsvTransLine* trans_line = NULL; for (j = 0; j < line->len; j++) { /* We do nothing in "None" or "Account" columns. */ if ((column_types->data[j] != GNC_CSV_NONE) && (column_types->data[j] != GNC_CSV_ACCOUNT)) { /* Affect the transaction appropriately. */ TransProperty* property = trans_property_new (column_types->data[j], list); gboolean succeeded = trans_property_set (property, line->pdata[j]); /* TODO Maybe move error handling to within TransPropertyList functions? */ if (succeeded) { trans_property_list_add (property); } else { errors = TRUE; error_message = g_strdup_printf (_("%s column could not be understood."), _(gnc_csv_column_type_strs[property->type])); trans_property_free (property); break; } } } /* If we had success, add the transaction to parse_data->transaction. */ if (!errors) { trans_line = trans_property_list_to_trans (list, &error_message); errors = trans_line == NULL; } trans_property_list_free (list); /* If there were errors, add this line to parse_data->error_lines. */ if (errors) { parse_data->error_lines = g_list_append (parse_data->error_lines, GINT_TO_POINTER(i)); /* If there's already an error message, we need to replace it. */ if (line->len > (int)(parse_data->orig_row_lengths->data[i])) { g_free(line->pdata[line->len - 1]); line->pdata[line->len - 1] = error_message; } else { /* Put the error message at the end of the line. */ g_ptr_array_add (line, error_message); } } else { /* If all went well, add this transaction to the list. */ trans_line->line_no = i; /* We keep the transactions sorted by date. We start at the end * of the list and go backward, simply because the file itself * is probably also sorted by date (but we need to handle the * exception anyway). */ /* If we can just put it at the end, do so and increment last_transaction. */ if (last_transaction == NULL || xaccTransGetDate (((GncCsvTransLine*)(last_transaction->data))->trans) <= xaccTransGetDate (trans_line->trans)) { parse_data->transactions = g_list_append (parse_data->transactions, trans_line); /* If this is the first transaction, we need to get last_transaction on track. */ if (last_transaction == NULL) last_transaction = parse_data->transactions; else /* Otherwise, we can just continue. */ last_transaction = g_list_next (last_transaction); } /* Otherwise, search backward for the correct spot. */ else { GList* insertion_spot = last_transaction; while (insertion_spot != NULL && xaccTransGetDate (((GncCsvTransLine*)(insertion_spot->data))->trans) > xaccTransGetDate (trans_line->trans)) { insertion_spot = g_list_previous (insertion_spot); } /* Move insertion_spot one location forward since we have to * use the g_list_insert_before function. */ if (insertion_spot == NULL) /* We need to handle the case of inserting at the beginning of the list. */ insertion_spot = parse_data->transactions; else insertion_spot = g_list_next (insertion_spot); parse_data->transactions = g_list_insert_before (parse_data->transactions, insertion_spot, trans_line); } } /* Increment to the next row. */ if (redo_errors) { /* Move to the next error line in the list. */ error_lines = g_list_next (error_lines); if (error_lines == NULL) i = parse_data->orig_lines->len; /* Don't continue the for loop. */ else i = GPOINTER_TO_INT(error_lines->data); } else { if (parse_data->skip_rows == FALSE) i++; else i = i + 2; } } /* If we have a balance column, set the appropriate amounts on the transactions. */ hasBalanceColumn = FALSE; for (i = 0; i < parse_data->column_types->len; i++) { if (parse_data->column_types->data[i] == GNC_CSV_BALANCE) { hasBalanceColumn = TRUE; break; } } if (hasBalanceColumn) { GList* transactions = parse_data->transactions; /* balance_offset is how much the balance currently in the account * differs from what it will be after the transactions are * imported. This will be sum of all the previous transactions for * any given transaction. */ gnc_numeric balance_offset = double_to_gnc_numeric (0.0, xaccAccountGetCommoditySCU (account), GNC_HOW_RND_ROUND_HALF_UP); while (transactions != NULL) { GncCsvTransLine* trans_line = (GncCsvTransLine*)transactions->data; if (trans_line->balance_set) { time64 date = xaccTransGetDate (trans_line->trans); /* Find what the balance should be by adding the offset to the actual balance. */ gnc_numeric existing_balance = gnc_numeric_add (balance_offset, xaccAccountGetBalanceAsOfDate (account, date), xaccAccountGetCommoditySCU (account), GNC_HOW_RND_ROUND_HALF_UP); /* The amount of the transaction is the difference between the new and existing balance. */ gnc_numeric amount = gnc_numeric_sub (trans_line->balance, existing_balance, xaccAccountGetCommoditySCU (account), GNC_HOW_RND_ROUND_HALF_UP); SplitList* splits = xaccTransGetSplitList (trans_line->trans); while (splits) { SplitList* next_splits = g_list_next (splits); xaccSplitDestroy ((Split*)splits->data); splits = next_splits; } trans_add_split (trans_line->trans, account, gnc_account_get_book (account), amount, trans_line->num); if (trans_line->num) g_free (trans_line->num); /* This new transaction needs to be added to the balance offset. */ balance_offset = gnc_numeric_add (balance_offset, amount, xaccAccountGetCommoditySCU (account), GNC_HOW_RND_ROUND_HALF_UP); } transactions = g_list_next (transactions); } } if (redo_errors) /* Now that we're at the end, we do the freeing. */ { g_list_free (begin_error_lines); } /* We need to resize parse_data->column_types since errors may have added columns. */ for (i = 0; i < parse_data->orig_lines->len; i++) { if (max_cols < ((GPtrArray*)(parse_data->orig_lines->pdata[i]))->len) max_cols = ((GPtrArray*)(parse_data->orig_lines->pdata[i]))->len; } i = parse_data->column_types->len; parse_data->column_types = g_array_set_size (parse_data->column_types, max_cols); for (; i < max_cols; i++) { parse_data->column_types->data[i] = GNC_CSV_NONE; } return 0; }
static gchar* node_and_account_equal (xmlNodePtr node, Account* act) { xmlNodePtr mark; while (g_strcmp0 ((char*)node->name, "text") == 0) { node = node->next; } if (!check_dom_tree_version (node, "2.0.0")) { return g_strdup ("version wrong. Not 2.0.0 or not there"); } if (!node->name || g_strcmp0 ((char*)node->name, "gnc:account")) { return g_strdup ("Name of toplevel node is bad"); } for (mark = node->xmlChildrenNode; mark; mark = mark->next) { if (g_strcmp0 ((char*)mark->name, "text") == 0) { } else if (g_strcmp0 ((char*)mark->name, "act:name") == 0) { if (!equals_node_val_vs_string (mark, xaccAccountGetName (act))) { return g_strdup ("names differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:id") == 0) { if (!equals_node_val_vs_guid (mark, xaccAccountGetGUID (act))) { return g_strdup ("ids differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:type") == 0) { gchar* txt; GNCAccountType type; txt = dom_tree_to_text (mark); if (!txt) { return g_strdup ("couldn't get type string"); } else if (!xaccAccountStringToType (txt, &type)) { g_free (txt); return g_strdup ("couldn't convert type string to int"); } else if (type != xaccAccountGetType (act)) { g_free (txt); return g_strdup ("types differ"); } else { g_free (txt); } } else if (g_strcmp0 ((char*)mark->name, "act:commodity") == 0) { /* This is somewhat BS, because if the commodity isn't a currency (and therefore built in) there isn't a corresponding currency in the XML, skip the test. jralls 2010-11-02 */ if (xaccAccountGetCommodity (act) == NULL) continue; if (!equals_node_val_vs_commodity ( mark, xaccAccountGetCommodity (act), gnc_account_get_book (act))) { return g_strdup ("commodities differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:code") == 0) { if (!equals_node_val_vs_string (mark, xaccAccountGetCode (act))) { return g_strdup ("codes differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:description") == 0) { if (!equals_node_val_vs_string ( mark, xaccAccountGetDescription (act))) { return g_strdup ("descriptions differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:slots") == 0) { /* xaccAccountDeleteOldData (act); */ if (!equals_node_val_vs_kvp_frame (mark, qof_instance_get_slots (QOF_INSTANCE (act)))) { return g_strdup ("slots differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:parent") == 0) { if (!equals_node_val_vs_guid ( mark, xaccAccountGetGUID (gnc_account_get_parent (act)))) { return g_strdup ("parent ids differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:commodity-scu") == 0) { if (!equals_node_val_vs_int (mark, xaccAccountGetCommoditySCU (act))) { return g_strdup ("commodity scus differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:hidden") == 0) { if (!equals_node_val_vs_boolean (mark, xaccAccountGetHidden (act))) { return g_strdup ("Hidden flags differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:placeholder") == 0) { if (!equals_node_val_vs_boolean (mark, xaccAccountGetPlaceholder (act))) { return g_strdup ("Placeholder flags differ"); } } else if (g_strcmp0 ((char*)mark->name, "act:security") == 0) { return NULL; // This tag is ignored. } else { return g_strdup_printf ("unknown node in dom tree: %s", mark->name); } } return NULL; }
Transaction * gnc_ab_trans_to_gnc(const AB_TRANSACTION *ab_trans, Account *gnc_acc) { QofBook *book; Transaction *gnc_trans; const gchar *fitid; const GWEN_TIME *valuta_date; time64 current_time; const char *custref; gchar *description; Split *split; gchar *memo; g_return_val_if_fail(ab_trans && gnc_acc, NULL); /* Create new GnuCash transaction for the given AqBanking one */ book = gnc_account_get_book(gnc_acc); gnc_trans = xaccMallocTransaction(book); xaccTransBeginEdit(gnc_trans); /* Date / Time */ valuta_date = AB_Transaction_GetValutaDate(ab_trans); if (!valuta_date) { const GWEN_TIME *normal_date = AB_Transaction_GetDate(ab_trans); if (normal_date) valuta_date = normal_date; } if (valuta_date) xaccTransSetDatePostedSecsNormalized(gnc_trans, GWEN_Time_toTime_t(valuta_date)); else g_warning("transaction_cb: Oops, date 'valuta_date' was NULL"); xaccTransSetDateEnteredSecs(gnc_trans, gnc_time (NULL)); /* Currency. We take simply the default currency of the gnucash account */ xaccTransSetCurrency(gnc_trans, xaccAccountGetCommodity(gnc_acc)); /* Trans-Num or Split-Action set with gnc_set_num_action below per book * option */ /* Description */ description = gnc_ab_description_to_gnc(ab_trans); xaccTransSetDescription(gnc_trans, description); g_free(description); /* Notes. */ /* xaccTransSetNotes(gnc_trans, g_notes); */ /* But Nobody ever uses the Notes field? */ /* Add one split */ split = xaccMallocSplit(book); xaccSplitSetParent(split, gnc_trans); xaccSplitSetAccount(split, gnc_acc); /* Set the transaction number or split action field based on book option. * We use the "customer reference", if there is one. */ custref = AB_Transaction_GetCustomerReference(ab_trans); if (custref && *custref && g_ascii_strncasecmp(custref, "NONREF", 6) != 0) gnc_set_num_action (gnc_trans, split, custref, NULL); /* Set OFX unique transaction ID */ fitid = AB_Transaction_GetFiId(ab_trans); if (fitid && *fitid) gnc_import_set_split_online_id(split, fitid); { /* Amount into the split */ const AB_VALUE *ab_value = AB_Transaction_GetValue(ab_trans); double d_value = ab_value ? AB_Value_GetValueAsDouble (ab_value) : 0.0; AB_TRANSACTION_TYPE ab_type = AB_Transaction_GetType (ab_trans); gnc_numeric gnc_amount; /*printf("Transaction with value %f has type %d\n", d_value, ab_type);*/ /* If the value is positive, but the transaction type says the money is transferred away from our account (Transfer instead of DebitNote), we switch the value to negative. */ if (d_value > 0.0 && ab_type == AB_Transaction_TypeTransfer) d_value = -d_value; gnc_amount = double_to_gnc_numeric( d_value, xaccAccountGetCommoditySCU(gnc_acc), GNC_HOW_RND_ROUND_HALF_UP); if (!ab_value) g_warning("transaction_cb: Oops, value was NULL. Using 0"); xaccSplitSetBaseValue(split, gnc_amount, xaccAccountGetCommodity(gnc_acc)); } /* Memo in the Split. */ memo = gnc_ab_memo_to_gnc(ab_trans); xaccSplitSetMemo(split, memo); g_free(memo); return gnc_trans; }
void TearDown() { qof_book_destroy (gnc_account_get_book (t_bank_account)); }
GNCLot * gncOwnerCreatePaymentLot (const GncOwner *owner, Transaction *txn, Account *posted_acc, Account *xfer_acc, gnc_numeric amount, gnc_numeric exch, Timespec date, const char *memo, const char *num) { QofBook *book; Split *split; const char *name; gnc_commodity *commodity; Split *xfer_split = NULL; GNCLot *payment_lot; /* Verify our arguments */ if (!owner || !posted_acc || !xfer_acc) return NULL; g_return_val_if_fail (owner->owner.undefined != NULL, NULL); /* Compute the ancillary data */ book = gnc_account_get_book (posted_acc); name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner)); commodity = gncOwnerGetCurrency (owner); // reverse = use_reversed_payment_amounts(owner); if (txn) { /* Pre-existing transaction was specified. We completely clear it, * except for the split in the transfer account, unless the * transaction can't be reused (wrong currency, wrong transfer account). * In that case, the transaction is simply removed and an new * one created. */ xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc); if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner)) { g_message("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction."); xfer_split = NULL; } if (!xfer_split) { g_message("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one."); xaccTransBeginEdit (txn); xaccTransDestroy (txn); xaccTransCommitEdit (txn); txn = NULL; } else { int i = 0; xaccTransBeginEdit (txn); while (i < xaccTransCountSplits(txn)) { Split *split = xaccTransGetSplit (txn, i); if (split == xfer_split) { gnc_set_num_action (NULL, split, num, _("Payment")); ++i; } else { xaccSplitDestroy(split); } } /* Note: don't commit transaction now - that would insert an imbalance split.*/ } } /* Create the transaction if we don't have one yet */ if (!txn) { txn = xaccMallocTransaction (book); xaccTransBeginEdit (txn); } /* Insert a split for the transfer account if we don't have one yet */ if (!xfer_split) { /* Set up the transaction */ xaccTransSetDescription (txn, name ? name : ""); /* set per book option */ xaccTransSetCurrency (txn, commodity); xaccTransSetDateEnteredSecs (txn, gnc_time (NULL)); xaccTransSetDatePostedTS (txn, &date); /* The split for the transfer account */ split = xaccMallocSplit (book); xaccSplitSetMemo (split, memo); /* set per book option */ gnc_set_num_action (NULL, split, num, _("Payment")); xaccAccountBeginEdit (xfer_acc); xaccAccountInsertSplit (xfer_acc, split); xaccAccountCommitEdit (xfer_acc); xaccTransAppendSplit (txn, split); if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity)) { xaccSplitSetBaseValue (split, amount, commodity); } else { /* Need to value the payment in terms of the owner commodity */ gnc_numeric payment_value = gnc_numeric_mul(amount, exch, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP); xaccSplitSetAmount(split, amount); xaccSplitSetValue(split, payment_value); } } /* Add a split in the post account */ split = xaccMallocSplit (book); xaccSplitSetMemo (split, memo); /* set per book option */ gnc_set_num_action (NULL, split, num, _("Payment")); xaccAccountBeginEdit (posted_acc); xaccAccountInsertSplit (posted_acc, split); xaccAccountCommitEdit (posted_acc); xaccTransAppendSplit (txn, split); xaccSplitSetBaseValue (split, gnc_numeric_neg (amount), commodity); /* Create a new lot for the payment */ payment_lot = gnc_lot_new (book); gncOwnerAttachToLot (owner, payment_lot); gnc_lot_add_split (payment_lot, split); /* Mark the transaction as a payment */ gnc_set_num_action (txn, NULL, num, _("Payment")); xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT); /* Commit this new transaction */ xaccTransCommitEdit (txn); return payment_lot; }
/** Create a Transaction from a TransPropertyList. * @param list The list of properties * @param error Contains an error on failure * @return On success, a GncCsvTransLine; on failure, the trans pointer is NULL */ static GncCsvTransLine* trans_property_list_to_trans (TransPropertyList* list, gchar** error) { GncCsvTransLine* trans_line = g_new (GncCsvTransLine, 1); GList* properties_begin = list->properties; QofBook* book = gnc_account_get_book (list->account); gnc_commodity* currency = xaccAccountGetCommodity (list->account); gnc_numeric amount = double_to_gnc_numeric (0.0, xaccAccountGetCommoditySCU (list->account), GNC_HOW_RND_ROUND_HALF_UP); gchar *num = NULL; /* This flag is set to TRUE if we can use the "Deposit" or "Withdrawal" column. */ gboolean amount_set = FALSE; /* The balance is 0 by default. */ trans_line->balance_set = FALSE; trans_line->balance = amount; trans_line->num = NULL; /* We make the line_no -1 just to mark that it hasn't been set. We * may get rid of line_no soon anyway, so it's not particularly * important. */ trans_line->line_no = -1; /* Make sure this is a transaction with all the columns we need. */ if (!trans_property_list_verify_essentials (list, error)) { g_free(trans_line); return NULL; } trans_line->trans = xaccMallocTransaction (book); xaccTransBeginEdit (trans_line->trans); xaccTransSetCurrency (trans_line->trans, currency); /* Go through each of the properties and edit the transaction accordingly. */ list->properties = properties_begin; while (list->properties != NULL) { TransProperty* prop = (TransProperty*)(list->properties->data); switch (prop->type) { case GNC_CSV_DATE: xaccTransSetDatePostedSecsNormalized (trans_line->trans, *((time64*)(prop->value))); break; case GNC_CSV_DESCRIPTION: xaccTransSetDescription (trans_line->trans, (char*)(prop->value)); break; case GNC_CSV_NOTES: xaccTransSetNotes (trans_line->trans, (char*)(prop->value)); break; case GNC_CSV_NUM: /* the 'num' is saved and passed to 'trans_add_split' below where * 'gnc_set_num_action' is used to set tran-num and/or split-action * per book option */ num = g_strdup ((char*)(prop->value)); /* the 'num' is also saved and used in 'gnc_csv_parse_to_trans' when * it calls 'trans_add_split' after deleting the splits added below * when a balance is used by the user */ trans_line->num = g_strdup ((char*)(prop->value)); break; case GNC_CSV_DEPOSIT: /* Add deposits to the existing amount. */ if (prop->value != NULL) { amount = gnc_numeric_add (*((gnc_numeric*)(prop->value)), amount, xaccAccountGetCommoditySCU (list->account), GNC_HOW_RND_ROUND_HALF_UP); amount_set = TRUE; /* We will use the "Deposit" and "Withdrawal" columns in preference to "Balance". */ trans_line->balance_set = FALSE; } break; case GNC_CSV_WITHDRAWAL: /* Withdrawals are just negative deposits. */ if (prop->value != NULL) { amount = gnc_numeric_add (gnc_numeric_neg(*((gnc_numeric*)(prop->value))), amount, xaccAccountGetCommoditySCU (list->account), GNC_HOW_RND_ROUND_HALF_UP); amount_set = TRUE; /* We will use the "Deposit" and "Withdrawal" columns in preference to "Balance". */ trans_line->balance_set = FALSE; } break; case GNC_CSV_BALANCE: /* The balance gets stored in a separate field in trans_line. */ /* We will use the "Deposit" and "Withdrawal" columns in preference to "Balance". */ if (!amount_set && prop->value != NULL) { /* This gets put into the actual transaction at the end of gnc_csv_parse_to_trans. */ trans_line->balance = *((gnc_numeric*)(prop->value)); trans_line->balance_set = TRUE; } break; } list->properties = g_list_next (list->properties); } /* Add a split with the cumulative amount value. */ trans_add_split (trans_line->trans, list->account, book, amount, num); if (num) g_free (num); return trans_line; }
void gnc_ab_maketrans(GtkWidget *parent, Account *gnc_acc, GncABTransType trans_type) { AB_BANKING *api; gboolean online = FALSE; AB_ACCOUNT *ab_acc; GList *templates = NULL; GncABTransDialog *td = NULL; gboolean successful = FALSE; gboolean aborted = FALSE; g_return_if_fail(parent && gnc_acc); /* Get the API */ api = gnc_AB_BANKING_new(); if (!api) { g_warning("gnc_ab_maketrans: Couldn't get AqBanking API"); return; } if (AB_Banking_OnlineInit(api #ifdef AQBANKING_VERSION_4_EXACTLY , 0 #endif ) != 0) { g_warning("gnc_ab_maketrans: Couldn't initialize AqBanking API"); goto cleanup; } online = TRUE; /* Get the AqBanking Account */ ab_acc = gnc_ab_get_ab_account(api, gnc_acc); if (!ab_acc) { g_warning("gnc_ab_gettrans: No AqBanking account found"); gnc_error_dialog(parent, _("No valid online banking account assigned.")); goto cleanup; } /* Get list of template transactions */ templates = gnc_ab_trans_templ_list_new_from_book( gnc_account_get_book(gnc_acc)); /* Create new ABTransDialog */ td = gnc_ab_trans_dialog_new(parent, ab_acc, xaccAccountGetCommoditySCU(gnc_acc), trans_type, templates); templates = NULL; /* Repeat until AqBanking action was successful or user pressed cancel */ do { GncGWENGui *gui = NULL; gint result; gboolean changed; const AB_TRANSACTION *ab_trans; AB_JOB *job = NULL; AB_JOB_LIST2 *job_list = NULL; XferDialog *xfer_dialog = NULL; gnc_numeric amount; gchar *description; gchar *memo; Transaction *gnc_trans = NULL; AB_IMEXPORTER_CONTEXT *context = NULL; AB_JOB_STATUS job_status; GncABImExContextImport *ieci = NULL; /* Get a GUI object */ gui = gnc_GWEN_Gui_get(parent); if (!gui) { g_warning("gnc_ab_maketrans: Couldn't initialize Gwenhywfar GUI"); aborted = TRUE; goto repeat; } /* Let the user enter the values */ result = gnc_ab_trans_dialog_run_until_ok(td); /* Save the templates */ templates = gnc_ab_trans_dialog_get_templ(td, &changed); if (changed) save_templates(parent, gnc_acc, templates, (result == GNC_RESPONSE_NOW)); g_list_free(templates); templates = NULL; if (result != GNC_RESPONSE_NOW && result != GNC_RESPONSE_LATER) { aborted = TRUE; goto repeat; } /* Get a job and enqueue it */ ab_trans = gnc_ab_trans_dialog_get_ab_trans(td); job = gnc_ab_trans_dialog_get_job(td); if (!job || AB_Job_CheckAvailability(job #ifndef AQBANKING_VERSION_5_PLUS , 0 #endif )) { if (!gnc_verify_dialog( parent, FALSE, "%s", _("The backend found an error during the preparation " "of the job. It is not possible to execute this job. \n" "\n" "Most probable the bank does not support your chosen " "job or your Online Banking account does not have the permission " "to execute this job. More error messages might be " "visible on your console log.\n" "\n" "Do you want to enter the job again?"))) aborted = TRUE; goto repeat; } job_list = AB_Job_List2_new(); AB_Job_List2_PushBack(job_list, job); /* Setup a Transfer Dialog for the GnuCash transaction */ xfer_dialog = gnc_xfer_dialog(gnc_ab_trans_dialog_get_parent(td), gnc_acc); switch (trans_type) { case SINGLE_DEBITNOTE: gnc_xfer_dialog_set_title( xfer_dialog, _("Online Banking Direct Debit Note")); gnc_xfer_dialog_lock_to_account_tree(xfer_dialog); break; case SINGLE_INTERNAL_TRANSFER: gnc_xfer_dialog_set_title( xfer_dialog, _("Online Banking Bank-Internal Transfer")); gnc_xfer_dialog_lock_from_account_tree(xfer_dialog); break; case SEPA_TRANSFER: gnc_xfer_dialog_set_title( xfer_dialog, _("Online Banking European (SEPA) Transfer")); gnc_xfer_dialog_lock_from_account_tree(xfer_dialog); break; case SEPA_DEBITNOTE: gnc_xfer_dialog_set_title( xfer_dialog, _("Online Banking European (SEPA) Debit Note")); gnc_xfer_dialog_lock_to_account_tree(xfer_dialog); break; case SINGLE_TRANSFER: default: gnc_xfer_dialog_set_title( xfer_dialog, _("Online Banking Transaction")); gnc_xfer_dialog_lock_from_account_tree(xfer_dialog); } gnc_xfer_dialog_set_to_show_button_active(xfer_dialog, TRUE); amount = double_to_gnc_numeric( AB_Value_GetValueAsDouble(AB_Transaction_GetValue(ab_trans)), xaccAccountGetCommoditySCU(gnc_acc), GNC_HOW_RND_ROUND_HALF_UP); gnc_xfer_dialog_set_amount(xfer_dialog, amount); gnc_xfer_dialog_set_amount_sensitive(xfer_dialog, FALSE); gnc_xfer_dialog_set_date_sensitive(xfer_dialog, FALSE); description = gnc_ab_description_to_gnc(ab_trans); gnc_xfer_dialog_set_description(xfer_dialog, description); g_free(description); memo = gnc_ab_memo_to_gnc(ab_trans); gnc_xfer_dialog_set_memo(xfer_dialog, memo); g_free(memo); gnc_xfer_dialog_set_txn_cb(xfer_dialog, txn_created_cb, &gnc_trans); /* And run it */ successful = gnc_xfer_dialog_run_until_done(xfer_dialog); /* On cancel, go back to the AB transaction dialog */ if (!successful || !gnc_trans) { successful = FALSE; goto repeat; } if (result == GNC_RESPONSE_NOW) { /* Create a context to store possible results */ context = AB_ImExporterContext_new(); gui = gnc_GWEN_Gui_get(parent); if (!gui) { g_warning("gnc_ab_maketrans: Couldn't initialize Gwenhywfar GUI"); aborted = TRUE; goto repeat; } /* Finally, execute the job */ AB_Banking_ExecuteJobs(api, job_list, context #ifndef AQBANKING_VERSION_5_PLUS , 0 #endif ); /* Ignore the return value of AB_Banking_ExecuteJobs(), as the job's * status always describes better whether the job was actually * transferred to and accepted by the bank. See also * http://lists.gnucash.org/pipermail/gnucash-de/2008-September/006389.html */ job_status = AB_Job_GetStatus(job); if (job_status != AB_Job_StatusFinished && job_status != AB_Job_StatusPending) { successful = FALSE; if (!gnc_verify_dialog( parent, FALSE, "%s", _("An error occurred while executing the job. Please check " "the log window for the exact error message.\n" "\n" "Do you want to enter the job again?"))) { aborted = TRUE; } } else { successful = TRUE; } if (successful) { /* Import the results, awaiting nothing */ ieci = gnc_ab_import_context(context, 0, FALSE, NULL, parent); } } /* Simply ignore any other case */ repeat: /* Clean up */ if (gnc_trans && !successful) { xaccTransBeginEdit(gnc_trans); xaccTransDestroy(gnc_trans); xaccTransCommitEdit(gnc_trans); gnc_trans = NULL; } if (ieci) g_free(ieci); if (context) AB_ImExporterContext_free(context); if (job_list) { AB_Job_List2_free(job_list); job_list = NULL; } if (job) { AB_Job_free(job); job = NULL; } if (gui) { gnc_GWEN_Gui_release(gui); gui = NULL; } } while (!successful && !aborted); cleanup: if (td) gnc_ab_trans_dialog_free(td); if (online) #ifdef AQBANKING_VERSION_4_EXACTLY AB_Banking_OnlineFini(api, 0); #else AB_Banking_OnlineFini(api); #endif gnc_AB_BANKING_fini(api); }
int ofx_proc_transaction_cb(struct OfxTransactionData data, void * transaction_user_data) { char dest_string[255]; time64 current_time = gnc_time (NULL); Account *account; Account *investment_account = NULL; Account *income_account = NULL; gchar *investment_account_text, *investment_account_onlineid; gnc_commodity *currency = NULL; gnc_commodity *investment_commodity = NULL; gnc_numeric gnc_amount, gnc_units; QofBook *book; Transaction *transaction; Split *split; gchar *notes, *tmp; g_assert(gnc_ofx_importer_gui); if (!data.account_id_valid) { PERR("account ID for this transaction is unavailable!"); return 0; } account = gnc_import_select_account(gnc_gen_trans_list_widget(gnc_ofx_importer_gui), data.account_id, 0, NULL, NULL, ACCT_TYPE_NONE, NULL, NULL); if (account == NULL) { PERR("Unable to find account for id %s", data.account_id); return 0; } /***** Validate the input strings to ensure utf8 *****/ if (data.name_valid) gnc_utf8_strip_invalid(data.name); if (data.memo_valid) gnc_utf8_strip_invalid(data.memo); if (data.check_number_valid) gnc_utf8_strip_invalid(data.check_number); if (data.reference_number_valid) gnc_utf8_strip_invalid(data.reference_number); /***** Create the transaction and setup transaction data *******/ book = gnc_account_get_book(account); transaction = xaccMallocTransaction(book); xaccTransBeginEdit(transaction); /* Note: Unfortunately libofx <= 0.9.5 will not report a missing * date field as an invalid one. Instead, it will report it as * valid and return a completely bogus date. Starting with * libofx-0.9.6 (not yet released as of 2012-09-09), it will still * be reported as valid but at least the date integer itself is * just plain zero. */ if (data.date_posted_valid && (data.date_posted != 0)) { /* The hopeful case: We have a posted_date */ xaccTransSetDatePostedSecsNormalized(transaction, data.date_posted); } else if (data.date_initiated_valid && (data.date_initiated != 0)) { /* No posted date? Maybe we have an initiated_date */ xaccTransSetDatePostedSecsNormalized(transaction, data.date_initiated); } else { /* Uh no, no valid date. As a workaround use today's date */ xaccTransSetDatePostedSecsNormalized(transaction, current_time); } xaccTransSetDateEnteredSecs(transaction, current_time); /* Put transaction name in Description, or memo if name unavailable */ if (data.name_valid) { xaccTransSetDescription(transaction, data.name); } else if (data.memo_valid) { xaccTransSetDescription(transaction, data.memo); } /* Put everything else in the Notes field */ notes = g_strdup_printf("OFX ext. info: "); if (data.transactiontype_valid) { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Trans type:", gnc_ofx_ttype_to_string(data.transactiontype)); g_free(tmp); } if (data.invtransactiontype_valid) { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Investment Trans type:", gnc_ofx_invttype_to_str(data.invtransactiontype)); g_free(tmp); } if (data.memo_valid && data.name_valid) /* Copy only if memo wasn't put in Description */ { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Memo:", data.memo); g_free(tmp); } if (data.date_funds_available_valid) { Timespec ts; timespecFromTime64(&ts, data.date_funds_available); gnc_timespec_to_iso8601_buff (ts, dest_string); tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Date funds available:", dest_string); g_free(tmp); } if (data.server_transaction_id_valid) { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Server trans ID (conf. number):", data.server_transaction_id); g_free(tmp); } if (data.standard_industrial_code_valid) { tmp = notes; notes = g_strdup_printf("%s%s%ld", tmp, "|Standard Industrial Code:", data.standard_industrial_code); g_free(tmp); } if (data.payee_id_valid) { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Payee ID:", data.payee_id); g_free(tmp); } //PERR("WRITEME: GnuCash ofx_proc_transaction():Add PAYEE and ADRESS here once supported by libofx! Notes=%s\n", notes); /* Ideally, gnucash should process the corrected transactions */ if (data.fi_id_corrected_valid) { PERR("WRITEME: GnuCash ofx_proc_transaction(): WARNING: This transaction corrected a previous transaction, but we created a new one instead!\n"); tmp = notes; notes = g_strdup_printf("%s%s%s%s", tmp, "|This corrects transaction #", data.fi_id_corrected, "but GnuCash didn't process the correction!"); g_free(tmp); } xaccTransSetNotes(transaction, notes); g_free(notes); if (data.account_ptr && data.account_ptr->currency_valid) { DEBUG("Currency from libofx: %s", data.account_ptr->currency); currency = gnc_commodity_table_lookup( gnc_get_current_commodities (), GNC_COMMODITY_NS_CURRENCY, data.account_ptr->currency); } else { DEBUG("Currency from libofx unavailable, defaulting to account's default"); currency = xaccAccountGetCommodity(account); } xaccTransSetCurrency(transaction, currency); if (data.amount_valid) { if (!data.invtransactiontype_valid) { /***** Process a normal transaction ******/ DEBUG("Adding split; Ordinary banking transaction, money flows from or into the source account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(account, split); gnc_amount = gnc_ofx_numeric_from_double_txn(data.amount, transaction); xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction)); /* set tran-num and/or split-action per book option */ if (data.check_number_valid) { gnc_set_num_action(transaction, split, data.check_number, NULL); } else if (data.reference_number_valid) { gnc_set_num_action(transaction, split, data.reference_number, NULL); } /* Also put the ofx transaction's memo in the * split's memo field */ if (data.memo_valid) { xaccSplitSetMemo(split, data.memo); } if (data.fi_id_valid) { gnc_import_set_split_online_id(split, data.fi_id); } } else if (data.unique_id_valid && data.security_data_valid && data.security_data_ptr != NULL && data.security_data_ptr->secname_valid) { gboolean choosing_account = TRUE; /********* Process an investment transaction **********/ /* Note that the ACCT_TYPE_STOCK account type should be replaced with something derived from data.invtranstype*/ // We have an investment transaction. First select the correct commodity. investment_commodity = gnc_import_select_commodity(data.unique_id, FALSE, NULL, NULL); if (investment_commodity != NULL) { // As we now have the commodity, select the account with that commodity. investment_account_text = g_strdup_printf( /* This string is a default account name. It MUST NOT contain the character ':' anywhere in it or in any translations. */ _("Stock account for security \"%s\""), data.security_data_ptr->secname); investment_account_onlineid = g_strdup_printf( "%s%s", data.account_id, data.unique_id); investment_account = gnc_import_select_account(NULL, investment_account_onlineid, 1, investment_account_text, investment_commodity, ACCT_TYPE_STOCK, NULL, NULL); // but use it only if that's really the right commodity if (investment_account && xaccAccountGetCommodity(investment_account) != investment_commodity) investment_account = NULL; // Loop until we either have an account, or the user pressed Cancel while (!investment_account && choosing_account) { // No account with correct commodity automatically found. // But are we in auto-create mode and already know a parent? if (auto_create_commodity && ofx_parent_account) { // Yes, so use that as parent when auto-creating the new account below. investment_account = ofx_parent_account; } else { // Let the user choose an account investment_account = gnc_import_select_account( gnc_gen_trans_list_widget(gnc_ofx_importer_gui), data.unique_id, TRUE, investment_account_text, investment_commodity, ACCT_TYPE_STOCK, NULL, &choosing_account); } // Does the chosen account have the right commodity? if (investment_account && xaccAccountGetCommodity(investment_account) != investment_commodity) { if (auto_create_commodity && xaccAccountTypesCompatible(xaccAccountGetType(investment_account), ACCT_TYPE_STOCK)) { // The user chose an account, but it does // not have the right commodity. Also, // auto-creation is on. Hence, we create a // new child account of the selected one, // and this one will have the right // commodity. Account *parent_account = investment_account; investment_account = gnc_ofx_new_account(investment_account_text, investment_commodity, parent_account, ACCT_TYPE_STOCK); if (investment_account) { gnc_import_set_acc_online_id(investment_account, data.unique_id); choosing_account = FALSE; ofx_parent_account = parent_account; } else { ofx_parent_account = NULL; } } else { // No account with matching commodity. Ask the user // whether to continue or abort. choosing_account = gnc_verify_dialog( gnc_gen_trans_list_widget(gnc_ofx_importer_gui), TRUE, "The chosen account \"%s\" does not have the correct " "currency/security \"%s\" (it has \"%s\" instead). " "This account cannot be used. " "Do you want to choose again?", xaccAccountGetName(investment_account), gnc_commodity_get_fullname(investment_commodity), gnc_commodity_get_fullname(xaccAccountGetCommodity(investment_account))); // We must also delete the online_id that was set in gnc_import_select_account() gnc_import_set_acc_online_id(investment_account, ""); investment_account = NULL; } } } if (!investment_account) { PERR("No investment account found for text: %s\n", investment_account_text); } g_free (investment_account_text); g_free (investment_account_onlineid); investment_account_text = NULL; if (investment_account != NULL && data.unitprice_valid && data.units_valid && ( data.invtransactiontype != OFX_INCOME ) ) { DEBUG("Adding investment split; Money flows from or into the stock account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(investment_account, split); gnc_amount = gnc_ofx_numeric_from_double (ofx_get_investment_amount(&data), investment_commodity); gnc_units = gnc_ofx_numeric_from_double (data.units, investment_commodity); xaccSplitSetAmount(split, gnc_units); xaccSplitSetValue(split, gnc_amount); /* set tran-num and/or split-action per book option */ if (data.check_number_valid) { gnc_set_num_action(transaction, split, data.check_number, NULL); } else if (data.reference_number_valid) { gnc_set_num_action(transaction, split, data.reference_number, NULL); } if (data.security_data_ptr->memo_valid) { xaccSplitSetMemo(split, data.security_data_ptr->memo); } if (data.fi_id_valid) { gnc_import_set_split_online_id(split, data.fi_id); } } else { if (investment_account) PERR("The investment account, units or unitprice was not found for the investment transaction"); } } else { PERR("Commodity not found for the investment transaction"); } if (data.invtransactiontype_valid && investment_account) { if (data.invtransactiontype == OFX_REINVEST || data.invtransactiontype == OFX_INCOME) { DEBUG("Now let's find an account for the destination split"); income_account = gnc_ofx_kvp_get_assoc_account(investment_account); if (income_account == NULL) { DEBUG("Couldn't find an associated income account"); investment_account_text = g_strdup_printf( /* This string is a default account name. It MUST NOT contain the character ':' anywhere in it or in any translations. */ _("Income account for security \"%s\""), data.security_data_ptr->secname); income_account = gnc_import_select_account( gnc_gen_trans_list_widget(gnc_ofx_importer_gui), NULL, 1, investment_account_text, currency, ACCT_TYPE_INCOME, NULL, NULL); gnc_ofx_kvp_set_assoc_account(investment_account, income_account); DEBUG("KVP written"); } else { DEBUG("Found at least one associated income account"); } } if (income_account != NULL && data.invtransactiontype == OFX_REINVEST) { DEBUG("Adding investment split; Money flows from the income account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(income_account, split); gnc_amount = gnc_ofx_numeric_from_double_txn (data.amount, transaction); xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction)); // Set split memo from ofx transaction name or memo gnc_ofx_set_split_memo(&data, split); } if (income_account != NULL && data.invtransactiontype == OFX_INCOME) { DEBUG("Adding investment split; Money flows from the income account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(income_account, split); gnc_amount = gnc_ofx_numeric_from_double_txn (-data.amount,/*OFX_INCOME amounts come in as positive numbers*/ transaction); xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction)); // Set split memo from ofx transaction name or memo gnc_ofx_set_split_memo(&data, split); } } if (data.invtransactiontype_valid && data.invtransactiontype != OFX_REINVEST) { DEBUG("Adding investment split; Money flows from or to the cash account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(account, split); gnc_amount = gnc_ofx_numeric_from_double_txn( -ofx_get_investment_amount(&data), transaction); xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction)); // Set split memo from ofx transaction name or memo gnc_ofx_set_split_memo(&data, split); } } /* Send transaction to importer GUI. */ if (xaccTransCountSplits(transaction) > 0) { DEBUG("%d splits sent to the importer gui", xaccTransCountSplits(transaction)); gnc_gen_trans_list_add_trans (gnc_ofx_importer_gui, transaction); } else { PERR("No splits in transaction (missing account?), ignoring."); xaccTransDestroy(transaction); xaccTransCommitEdit(transaction); } } else { PERR("The transaction doesn't have a valid amount"); xaccTransDestroy(transaction); xaccTransCommitEdit(transaction); } return 0; }//end ofx_proc_transaction()