gnc_numeric gnc_convert_from_euro(const gnc_commodity * currency, gnc_numeric value) { gnc_euro_rate_struct * result; if (currency == NULL) return gnc_numeric_zero (); if (!gnc_commodity_is_iso(currency)) return gnc_numeric_zero (); result = bsearch(currency, gnc_euro_rates, sizeof(gnc_euro_rates) / sizeof(gnc_euro_rate_struct), sizeof(gnc_euro_rate_struct), gnc_euro_rate_compare); if (result == NULL) return gnc_numeric_zero (); { gnc_numeric rate; rate = double_to_gnc_numeric (result->rate, 100000, GNC_HOW_RND_ROUND_HALF_UP); /* EC Regulation 1103/97 states we should use "Round half away from zero" * See http://europa.eu/legislation_summaries/economic_and_monetary_affairs/institutional_and_economic_framework/l25025_en.htm */ return gnc_numeric_mul (value, rate, gnc_commodity_get_fraction (currency), GNC_HOW_RND_ROUND_HALF_UP); } }
static void _set_var_to_random_value(gchar *key, GncSxVariable *var, gpointer unused_user_data) { var->value = double_to_gnc_numeric(rand() + 2, 1, GNC_NUMERIC_RND_MASK | GNC_RND_FLOOR); }
static void check_double (void) { double flo; gnc_numeric val = gnc_numeric_create (0, 1); check_unary_op (gnc_numeric_eq, gnc_numeric_create (112346, 100000), double_to_gnc_numeric(1.1234567890123, GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND), val, "expected %s = %s double 6 figs"); check_unary_op (gnc_numeric_eq, gnc_numeric_create (112346, 10000000), double_to_gnc_numeric(0.011234567890123, GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND), val, "expected %s = %s double 6 figs"); check_unary_op (gnc_numeric_eq, gnc_numeric_create (112346, 100), double_to_gnc_numeric(1123.4567890123, GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND), val, "expected %s = %s double 6 figs"); check_unary_op (gnc_numeric_eq, gnc_numeric_create (112346, 10000000000LL), double_to_gnc_numeric(1.1234567890123e-5, GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND), val, "expected %s = %s double 6 figs"); flo = gnc_numeric_to_double(gnc_numeric_create(7, 16)); do_test ((0.4375 == flo), "float pt conversion"); }
/* Copy the values in the financial_info structure to the GUI */ static void fi_to_gui(FinCalcDialog *fcd) { const gnc_commodity *commodity; static char string[64]; gnc_numeric total; gnc_numeric npp; gnc_numeric pmt; int i; if (fcd == NULL) return; npp = gnc_numeric_create (fcd->financial_info.npp, 1); gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(fcd->amounts[PAYMENT_PERIODS]), npp); gnc_amount_edit_set_damount (GNC_AMOUNT_EDIT(fcd->amounts[INTEREST_RATE]), fcd->financial_info.ir); gnc_amount_edit_set_damount (GNC_AMOUNT_EDIT(fcd->amounts[PRESENT_VALUE]), fcd->financial_info.pv); gnc_amount_edit_set_damount (GNC_AMOUNT_EDIT(fcd->amounts[PERIODIC_PAYMENT]), fcd->financial_info.pmt); gnc_amount_edit_set_damount (GNC_AMOUNT_EDIT(fcd->amounts[FUTURE_VALUE]), -fcd->financial_info.fv); pmt = double_to_gnc_numeric (fcd->financial_info.pmt, 100000, GNC_HOW_RND_ROUND_HALF_UP); commodity = gnc_default_currency (); total = gnc_numeric_mul (npp, pmt, gnc_commodity_get_fraction (commodity), GNC_HOW_RND_ROUND_HALF_UP); xaccSPrintAmount (string, total, gnc_default_print_info (FALSE)); gtk_label_set_text (GTK_LABEL(fcd->payment_total_label), string); i = normalize_period(&fcd->financial_info.CF); gtk_combo_box_set_active(GTK_COMBO_BOX(fcd->compounding_combo), i); i = normalize_period(&fcd->financial_info.PF); gtk_combo_box_set_active(GTK_COMBO_BOX(fcd->payment_combo), i); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fcd->end_of_period_radio), !fcd->financial_info.bep); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(fcd->discrete_compounding_radio), fcd->financial_info.disc); }
gnc_numeric gnc_euro_currency_get_rate (const gnc_commodity *currency) { gnc_euro_rate_struct * result; if (currency == NULL) return gnc_numeric_zero (); if (!gnc_commodity_is_iso(currency)) return gnc_numeric_zero (); result = bsearch(currency, gnc_euro_rates, sizeof(gnc_euro_rates) / sizeof(gnc_euro_rate_struct), sizeof(gnc_euro_rate_struct), gnc_euro_rate_compare); if (result == NULL) return gnc_numeric_zero (); return double_to_gnc_numeric (result->rate, GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND_HALF_UP); }
/** 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; }
/** 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 AB_IMEXPORTER_ACCOUNTINFO * bal_accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data) { GncABImExContextImport *data = user_data; Account *gnc_acc; AB_ACCOUNT_STATUS *item, *best = NULL; const GWEN_TIME *best_time = NULL; const AB_BALANCE *booked_bal, *noted_bal; const AB_VALUE *booked_val = NULL, *noted_val = NULL; gdouble booked_value, noted_value; gnc_numeric value; time64 booked_tt = 0; GtkWidget *dialog; gboolean show_recn_window = FALSE; g_return_val_if_fail(element && data, NULL); if (data->awaiting & IGNORE_BALANCES) /* Ignore them */ return NULL; if (!AB_ImExporterAccountInfo_GetFirstAccountStatus(element)) /* No balance found */ return NULL; else data->awaiting |= FOUND_BALANCES; /* Lookup the most recent ACCOUNT_STATUS available */ item = AB_ImExporterAccountInfo_GetFirstAccountStatus(element); while (item) { const GWEN_TIME *item_time = AB_AccountStatus_GetTime(item); if (!best || GWEN_Time_Diff(best_time, item_time) < 0.0) { best = item; best_time = item_time; } item = AB_ImExporterAccountInfo_GetNextAccountStatus(element); } booked_bal = AB_AccountStatus_GetBookedBalance(best); if (!(data->awaiting & AWAIT_BALANCES)) { /* Ignore zero balances if we don't await a balance */ if (!booked_bal || AB_Value_IsZero(AB_Balance_GetValue(booked_bal))) return NULL; /* Ask the user whether to import unawaited non-zero balance */ if (gnc_verify_dialog(data->parent, TRUE, "%s", _("The bank has sent balance information " "in its response." "\n" "Do you want to import it?"))) { data->awaiting |= AWAIT_BALANCES; } else { data->awaiting |= IGNORE_BALANCES; return NULL; } } /* Lookup the corresponding gnucash account */ gnc_acc = gnc_ab_accinfo_to_gnc_acc(element); if (!gnc_acc) return NULL; data->gnc_acc = gnc_acc; /* Lookup booked balance and time */ if (booked_bal) { const GWEN_TIME *ti = AB_Balance_GetTime(booked_bal); if (ti) { booked_tt = GWEN_Time_toTime_t(ti); } else { /* No time found? Use today because the HBCI query asked for today's * balance. */ booked_tt = gnc_time64_get_day_start(gnc_time(NULL)); } booked_val = AB_Balance_GetValue(booked_bal); if (booked_val) { booked_value = AB_Value_GetValueAsDouble(booked_val); } else { g_warning("bal_accountinfo_cb: booked_val == NULL. Assuming 0"); booked_value = 0.0; } } else { g_warning("bal_accountinfo_cb: booked_bal == NULL. Assuming 0"); booked_tt = 0; booked_value = 0.0; } /* Lookup noted balance */ noted_bal = AB_AccountStatus_GetNotedBalance(best); if (noted_bal) { noted_val = AB_Balance_GetValue(noted_bal); if (noted_val) noted_value = AB_Value_GetValueAsDouble(noted_val); else { g_warning("bal_accountinfo_cb: noted_val == NULL. Assuming 0"); noted_value = 0.0; } } else { g_warning("bal_accountinfo_cb: noted_bal == NULL. Assuming 0"); noted_value = 0.0; } value = double_to_gnc_numeric(booked_value, xaccAccountGetCommoditySCU(gnc_acc), GNC_HOW_RND_ROUND_HALF_UP); if (noted_value == 0.0 && booked_value == 0.0) { dialog = gtk_message_dialog_new( GTK_WINDOW(data->parent), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", /* Translators: Strings from this file are needed only in * countries that have one of aqbanking's Online Banking * techniques available. This is 'OFX DirectConnect' * (U.S. and others), 'HBCI' (in Germany), or 'YellowNet' * (Switzerland). If none of these techniques are available * in your country, you may safely ignore strings from the * import-export/hbci subdirectory. */ _("The downloaded Online Banking Balance was zero.\n\n" "Either this is the correct balance, or your bank does not " "support Balance download in this Online Banking version. " "In the latter case you should choose a different " "Online Banking version number in the Online Banking " "(AqBanking or HBCI) Setup. After that, try again to " "download the Online Banking Balance.")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } else { gnc_numeric reconc_balance = xaccAccountGetReconciledBalance(gnc_acc); gchar *booked_str = gnc_AB_VALUE_to_readable_string(booked_val); gchar *message1 = g_strdup_printf( _("Result of Online Banking job: \n" "Account booked balance is %s"), booked_str); gchar *message2 = (noted_value == 0.0) ? g_strdup("") : g_strdup_printf(_("For your information: This account also " "has a noted balance of %s\n"), gnc_AB_VALUE_to_readable_string(noted_val)); if (gnc_numeric_equal(value, reconc_balance)) { const gchar *message3 = _("The booked balance is identical to the current " "reconciled balance of the account."); dialog = gtk_message_dialog_new( GTK_WINDOW(data->parent), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s\n%s\n%s", message1, message2, message3); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(GTK_WIDGET(dialog)); } else { const char *message3 = _("Reconcile account now?"); show_recn_window = gnc_verify_dialog(data->parent, TRUE, "%s\n%s\n%s", message1, message2, message3); } g_free(booked_str); g_free(message1); g_free(message2); } /* Show reconciliation window */ if (show_recn_window) recnWindowWithBalance(data->parent, gnc_acc, value, booked_tt); 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 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); }
/** Sets the value of the property by parsing str. Note: this should * only be called once on an instance of TransProperty, as calling it * more than once can cause memory leaks. * @param prop The property being set * @param str The string to be parsed * @return TRUE on success, FALSE on failure */ static gboolean trans_property_set(TransProperty* prop, char* str) { char *endptr, *possible_currency_symbol, *str_dupe; double value; switch (prop->type) { case GNC_CSV_DATE: prop->value = g_new(time_t, 1); *((time_t*)(prop->value)) = parse_date(str, prop->list->date_format); return *((time_t*)(prop->value)) != -1; case GNC_CSV_DESCRIPTION: case GNC_CSV_NUM: prop->value = g_strdup(str); return TRUE; case GNC_CSV_BALANCE: case GNC_CSV_DEPOSIT: case GNC_CSV_WITHDRAWAL: str_dupe = g_strdup(str); /* First, we make a copy so we can't mess up real data. */ /* Go through str_dupe looking for currency symbols. */ for (possible_currency_symbol = str_dupe; *possible_currency_symbol; possible_currency_symbol = g_utf8_next_char(possible_currency_symbol)) { if (g_unichar_type(g_utf8_get_char(possible_currency_symbol)) == G_UNICODE_CURRENCY_SYMBOL) { /* If we find a currency symbol, save the position just ahead * of the currency symbol (next_symbol), and find the null * terminator of the string (last_symbol). */ char *next_symbol = g_utf8_next_char(possible_currency_symbol), *last_symbol = next_symbol; while (*last_symbol) last_symbol = g_utf8_next_char(last_symbol); /* Move all of the string (including the null byte, which is * why we have +1 in the size parameter) following the * currency symbol back one character, thereby overwriting the * currency symbol. */ memmove(possible_currency_symbol, next_symbol, last_symbol - next_symbol + 1); break; } } /* Translate the string (now clean of currency symbols) into a number. */ value = strtod(str_dupe, &endptr); /* If this isn't a valid numeric string, this is an error. */ if (endptr != str_dupe + strlen(str_dupe)) { g_free(str_dupe); return FALSE; } g_free(str_dupe); if (abs(value) > 0.00001) { prop->value = g_new(gnc_numeric, 1); *((gnc_numeric*)(prop->value)) = double_to_gnc_numeric(value, xaccAccountGetCommoditySCU(prop->list->account), GNC_RND_ROUND); } return TRUE; } return FALSE; /* We should never actually get here. */ }
static void* func_op(const char *fname, int argc, void **argv) { SCM scmFn, scmArgs, scmTmp; int i; var_store *vs; gchar *str; gnc_numeric n, *result; GString *realFnName; realFnName = g_string_sized_new( strlen(fname) + 5 ); g_string_printf( realFnName, "gnc:%s", fname ); scmFn = scm_internal_catch(SCM_BOOL_T, (scm_t_catch_body)scm_c_eval_string, realFnName->str, scm_handle_by_message_noexit, NULL); g_string_free( realFnName, TRUE ); if (!scm_is_procedure(scmFn)) { /* FIXME: handle errors correctly. */ printf( "gnc:\"%s\" is not a scm procedure\n", fname ); return NULL; } scmArgs = scm_listify( SCM_UNDEFINED ); for ( i = 0; i < argc; i++ ) { /* cons together back-to-front. */ vs = (var_store*)argv[argc - i - 1]; switch ( vs->type ) { case VST_NUMERIC: n = *(gnc_numeric*)(vs->value); scmTmp = scm_make_real( gnc_numeric_to_double( n ) ); break; case VST_STRING: str = (char*)(vs->value); scmTmp = scm_mem2string( str, strlen(str) ); break; default: /* FIXME: error */ printf( "argument %d not a numeric or string [type = %d]\n", i, vs->type ); return NULL; break; /* notreached */ } scmArgs = scm_cons( scmTmp, scmArgs ); } //scmTmp = scm_apply(scmFn, scmArgs , SCM_EOL); scmTmp = gfec_apply(scmFn, scmArgs, _exception_handler); if (_function_evaluation_error_msg != NULL) { PERR("function eval error: [%s]\n", _function_evaluation_error_msg); _function_evaluation_error_msg = NULL; return NULL; } result = g_new0( gnc_numeric, 1 ); *result = double_to_gnc_numeric( scm_num2dbl(scmTmp, G_STRFUNC), GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND ); /* FIXME: cleanup scmArgs = scm_list, cons'ed cells? */ return (void*)result; }
static gnc_numeric gnc_ofx_numeric_from_double(double value, const gnc_commodity *commodity) { return double_to_gnc_numeric (value, gnc_commodity_get_fraction(commodity), GNC_HOW_RND_ROUND_HALF_UP); }