/** * Update start date... right now we always base this off the transaction * start date, but ideally we want to respect what the user has in the field, * somehow. **/ static void sxftd_freq_combo_changed( GtkWidget *w, gpointer user_data ) { SXFromTransInfo *sxfti = (SXFromTransInfo*)user_data; GDate date, nextDate; time_t tmp_tt; struct tm *tmpTm; GList *schedule = NULL; tmp_tt = xaccTransGetDate( sxfti->trans ); g_date_set_time_t( &date, tmp_tt ); g_date_clear(&nextDate, 1); sxftd_update_schedule(sxfti, &date, &schedule); recurrenceListNextInstance(schedule, &date, &nextDate); tmpTm = g_new0( struct tm, 1 ); g_date_to_struct_tm( &nextDate, tmpTm ); tmp_tt = mktime( tmpTm ); g_free( tmpTm ); gnc_date_edit_set_time( sxfti->startDateGDE, tmp_tt ); recurrenceListFree(&schedule); sxftd_update_example_cal( sxfti ); }
gboolean xaccScrubMergeSubSplits (Split *split, gboolean strict) { gboolean rc = FALSE; Transaction *txn; SplitList *node; GNCLot *lot; if (strict && (FALSE == is_subsplit (split))) return FALSE; txn = split->parent; // Don't mess with splits from an invoice transaction // Those are the responsibility of the business code if (gncInvoiceGetInvoiceFromTxn (txn)) return FALSE; lot = xaccSplitGetLot (split); ENTER ("(Lot=%s)", gnc_lot_get_title(lot)); restart: for (node = txn->splits; node; node = node->next) { Split *s = node->data; if (xaccSplitGetLot (s) != lot) continue; if (s == split) continue; if (qof_instance_get_destroying(s)) continue; // Don't mess with splits from an invoice transaction // Those are the responsibility of the business code if (gncInvoiceGetInvoiceFromTxn (s->parent)) return FALSE; if (strict) { /* OK, this split is in the same lot (and thus same account) * as the indicated split. Make sure it is really a subsplit * of the split we started with. It's possible to have two * splits in the same lot and transaction that are not subsplits * of each other, the test-period test suite does this, for * example. Only worry about adjacent sub-splits. By * repeatedly merging adjacent subsplits, we'll get the non- * adjacent ones too. */ if (!xaccSplitIsPeerSplit (split, s)) continue; } merge_splits (split, s); rc = TRUE; goto restart; } if (rc && gnc_numeric_zero_p (split->amount)) { time64 pdate = xaccTransGetDate (txn); gchar *pdatestr = gnc_ctime (&pdate); PWARN ("Result of merge has zero amt!"); PWARN ("Transaction details - posted date %s - description %s", pdatestr, xaccTransGetDescription(txn)); g_free (pdatestr); } LEAVE (" splits merged=%d", rc); return rc; }
// Transaction line starts with Date static gchar* begin_trans_string (Transaction *trans, CsvExportInfo *info) { gchar *date = qof_print_date (xaccTransGetDate (trans)); gchar *result = g_strconcat (info->end_sep, date, info->mid_sep, NULL); g_free (date); return result; }
void xaccTransScrubPostedDate (Transaction *trans) { time64 orig = xaccTransGetDate(trans); GDate date = xaccTransGetDatePostedGDate(trans); Timespec ts = gdate_to_timespec(date); if (orig && orig != ts.tv_sec) { /* xaccTransSetDatePostedTS handles committing the change. */ xaccTransSetDatePostedTS(trans, &ts); } }
void GncTxImport::create_transaction (std::vector<parse_line_t>::iterator& parsed_line) { StrVec line; std::string error_message; std::shared_ptr<GncPreTrans> trans_props = nullptr; std::shared_ptr<GncPreSplit> split_props = nullptr; bool skip_line = false; std::tie(line, error_message, trans_props, split_props, skip_line) = *parsed_line; if (skip_line) return; error_message.clear(); // Add an ACCOUNT property with the default account if no account column was set by the user auto line_acct = split_props->get_account(); if (!line_acct) { if (m_settings.m_base_account) split_props->set_account(m_settings.m_base_account); else { // Oops - the user didn't select an Account column *and* we didn't get a default value either! // Note if you get here this suggests a bug in the code! error_message = _("No account column selected and no default account specified either.\n" "This should never happen. Please report this as a bug."); PINFO("User warning: %s", error_message.c_str()); throw std::invalid_argument(error_message); } } /* If column parsing was successful, convert trans properties into a draft transaction. */ try { trans_properties_verify_essentials (parsed_line); /* If all went well, add this transaction to the list. */ auto draft_trans = trans_properties_to_trans (parsed_line); if (draft_trans) { auto trans_date = xaccTransGetDate (draft_trans->trans); m_transactions.insert (std::pair<time64, std::shared_ptr<DraftTransaction>>(trans_date,std::move(draft_trans))); } } catch (const std::invalid_argument& e) { error_message = e.what(); PINFO("User warning: %s", error_message.c_str()); } }
void xaccTransScrubPostedDate (Transaction *trans) { time64 orig = xaccTransGetDate(trans); if(orig == INT64_MAX) { GDate date = xaccTransGetDatePostedGDate(trans); time64 time = gdate_to_time64(date); if(time != INT64_MAX) { // xaccTransSetDatePostedSecs handles committing the change. xaccTransSetDatePostedSecs(trans, time); } } }
/** * Update start date... right now we always base this off the transaction * start date, but ideally we want to respect what the user has in the field, * somehow. **/ static void sxftd_freq_combo_changed( GtkWidget *w, gpointer user_data ) { SXFromTransInfo *sxfti = (SXFromTransInfo*)user_data; GDate date, nextDate; time64 tmp_tt; GList *schedule = NULL; tmp_tt = xaccTransGetDate( sxfti->trans ); gnc_gdate_set_time64 (&date, tmp_tt); g_date_clear(&nextDate, 1); sxftd_update_schedule(sxfti, &date, &schedule); recurrenceListNextInstance(schedule, &date, &nextDate); tmp_tt = gnc_time64_get_day_start_gdate (&nextDate); gnc_date_edit_set_time( sxfti->startDateGDE, tmp_tt ); recurrenceListFree(&schedule); sxftd_update_example_cal( sxfti ); }
/********************************************************************\ * gnc_reconcile_view_postpone * * postpone the reconcile information in the view by setting * * reconciled splits to cleared status * * * * Args: view - view to commit * * Returns: nothing * \********************************************************************/ void gnc_reconcile_view_postpone (GNCReconcileView *view) { GtkTreeModel *model; GtkTreeIter iter; int num_splits; int i; gpointer entry = NULL; g_return_if_fail (view != NULL); g_return_if_fail (GNC_IS_RECONCILE_VIEW (view)); if (view->reconciled == NULL) return; model = gtk_tree_view_get_model (GTK_TREE_VIEW (GNC_QUERY_VIEW (view))); gtk_tree_model_get_iter_first (model, &iter); num_splits = gnc_query_view_get_num_entries (GNC_QUERY_VIEW (view)); gnc_suspend_gui_refresh(); for (i = 0; i < num_splits; i++) { char recn; gtk_tree_model_get (model, &iter, REC_POINTER, &entry, -1); // Don't change splits past reconciliation date that haven't been // set to be reconciled if (gnc_difftime (view->statement_date, xaccTransGetDate (xaccSplitGetParent (entry))) >= 0 || g_hash_table_lookup (view->reconciled, entry)) { recn = g_hash_table_lookup (view->reconciled, entry) ? CREC : NREC; xaccSplitSetReconcile (entry, recn); } gtk_tree_model_iter_next (model, &iter); } gnc_resume_gui_refresh(); }
static gboolean gncScrubLotDanglingPayments (GNCLot *lot) { SplitList * split_list, *filtered_list = NULL, *match_list = NULL, *node; Split *ll_split = gnc_lot_get_earliest_split (lot); Transaction *ll_trans = xaccSplitGetParent (ll_split); gnc_numeric ll_val = xaccSplitGetValue (ll_split); time64 ll_date = xaccTransGetDate (ll_trans); const char *ll_desc = xaccTransGetDescription (ll_trans); // look for free splits (i.e. not in any lot) which, // compared to the lot link split // - have the same date // - have the same description // - have an opposite sign amount // - free split's abs value is less than or equal to ll split's abs value split_list = xaccAccountGetSplitList(gnc_lot_get_account (lot)); for (node = split_list; node; node = node->next) { Split *free_split = node->data; Transaction *free_trans; gnc_numeric free_val; if (NULL != xaccSplitGetLot(free_split)) continue; free_trans = xaccSplitGetParent (free_split); if (ll_date != xaccTransGetDate (free_trans)) continue; if (0 != g_strcmp0 (ll_desc, xaccTransGetDescription (free_trans))) continue; free_val = xaccSplitGetValue (free_split); if (gnc_numeric_positive_p (ll_val) == gnc_numeric_positive_p (free_val)) continue; if (gnc_numeric_compare (gnc_numeric_abs (free_val), gnc_numeric_abs (ll_val)) > 0) continue; filtered_list = g_list_append(filtered_list, free_split); } match_list = gncSLFindOffsSplits (filtered_list, ll_val); g_list_free (filtered_list); for (node = match_list; node; node = node->next) { Split *match_split = node->data; gnc_lot_add_split (lot, match_split); } if (match_list) { g_list_free (match_list); return TRUE; } else return FALSE; }
static gint sxftd_init( SXFromTransInfo *sxfti ) { GtkWidget *w; const char *transName; gint pos; GList *schedule = NULL; time64 start_tt; struct tm *tmpTm; GDate date, nextDate; if ( ! sxfti->sx ) { return -1; } if ( ! sxfti->trans ) { return -2; } if ( xaccTransIsOpen( sxfti->trans ) ) { return SXFTD_ERRNO_OPEN_XACTION; } /* Setup Widgets */ { sxfti->ne_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "never_end_button")); sxfti->ed_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "end_on_date_button")); sxfti->oc_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "n_occurrences_button")); sxfti->n_occurences = GTK_ENTRY(gtk_builder_get_object(sxfti->builder, "n_occurrences_entry")); } /* Get the name from the transaction, try that as the initial SX name. */ transName = xaccTransGetDescription( sxfti->trans ); xaccSchedXactionSetName( sxfti->sx, transName ); sxfti->name = GTK_ENTRY(gtk_builder_get_object(sxfti->builder, "name_entry" )); pos = 0; gtk_editable_insert_text( GTK_EDITABLE(sxfti->name), transName, (strlen(transName) * sizeof(char)), &pos ); sxfti_attach_callbacks(sxfti); /* Setup the example calendar and related data structures. */ { int num_marks = SXFTD_EXCAL_NUM_MONTHS * 31; w = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "ex_cal_frame" )); sxfti->dense_cal_model = gnc_dense_cal_store_new(num_marks); sxfti->example_cal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(sxfti->dense_cal_model))); g_object_ref_sink(sxfti->example_cal); g_assert(sxfti->example_cal); gnc_dense_cal_set_num_months( sxfti->example_cal, SXFTD_EXCAL_NUM_MONTHS ); gnc_dense_cal_set_months_per_col( sxfti->example_cal, SXFTD_EXCAL_MONTHS_PER_COL ); gtk_container_add( GTK_CONTAINER(w), GTK_WIDGET(sxfti->example_cal) ); } /* Setup the start and end dates as GNCDateEdits */ { GtkWidget *paramTable = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "param_table" )); sxfti->startDateGDE = GNC_DATE_EDIT( gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE)); gtk_table_attach( GTK_TABLE(paramTable), GTK_WIDGET( sxfti->startDateGDE ), 1, 2, 2, 3, (GTK_EXPAND | GTK_FILL), GTK_FILL, 0, 0 ); g_signal_connect( sxfti->startDateGDE, "date-changed", G_CALLBACK( sxftd_update_excal_adapt ), sxfti ); } { GtkWidget *endDateBox = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "end_date_hbox" )); sxfti->endDateGDE = GNC_DATE_EDIT( gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE)); gtk_box_pack_start( GTK_BOX( endDateBox ), GTK_WIDGET( sxfti->endDateGDE ), TRUE, TRUE, 0 ); g_signal_connect( sxfti->endDateGDE, "date-changed", G_CALLBACK( sxftd_update_excal_adapt ), sxfti ); } /* Setup the initial start date for user display/confirmation */ /* compute good initial date. */ start_tt = xaccTransGetDate( sxfti->trans ); gnc_gdate_set_time64( &date, start_tt ); sxfti->freq_combo = GTK_COMBO_BOX(gtk_builder_get_object(sxfti->builder, "freq_combo_box")); gtk_combo_box_set_active(GTK_COMBO_BOX(sxfti->freq_combo), 0); g_signal_connect( sxfti->freq_combo, "changed", G_CALLBACK(sxftd_freq_combo_changed), sxfti ); sxftd_update_schedule( sxfti, &date, &schedule); recurrenceListNextInstance(schedule, &date, &nextDate); recurrenceListFree(&schedule); start_tt = gnc_time64_get_day_start_gdate (&nextDate); gnc_date_edit_set_time( sxfti->startDateGDE, start_tt ); g_signal_connect( G_OBJECT(sxfti->name), "destroy", G_CALLBACK(sxftd_destroy), sxfti ); sxftd_update_example_cal( sxfti ); return 0; }
void gnc_split_register_load (SplitRegister *reg, GList * slist, Account *default_account) { SRInfo *info; Transaction *pending_trans; CursorBuffer *cursor_buffer; GHashTable *trans_table = NULL; CellBlock *cursor_header; CellBlock *lead_cursor; CellBlock *split_cursor; Transaction *blank_trans; Transaction *find_trans; Transaction *trans; CursorClass find_class; Split *find_trans_split; Split *blank_split; Split *find_split; Split *split; Table *table; GList *node; gboolean start_primary_color = TRUE; gboolean found_pending = FALSE; gboolean need_divider_upper = FALSE; gboolean found_divider_upper = FALSE; gboolean found_divider = FALSE; gboolean has_last_num = FALSE; gboolean multi_line; gboolean dynamic; gboolean we_own_slist = FALSE; gboolean use_autoreadonly = qof_book_uses_autoreadonly(gnc_get_current_book()); VirtualCellLocation vcell_loc; VirtualLocation save_loc; int new_trans_split_row = -1; int new_trans_row = -1; int new_split_row = -1; time64 present, autoreadonly_time = 0; g_return_if_fail(reg); table = reg->table; g_return_if_fail(table); info = gnc_split_register_get_info (reg); g_return_if_fail(info); ENTER("reg=%p, slist=%p, default_account=%p", reg, slist, default_account); blank_split = xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ()); pending_trans = xaccTransLookup (&info->pending_trans_guid, gnc_get_current_book ()); /* make sure we have a blank split */ if (blank_split == NULL) { /* Wouldn't it be a bug to open the new transaction if there was * already a pending transaction? */ g_assert(pending_trans == NULL); blank_split = create_blank_split (default_account, info); } blank_trans = xaccSplitGetParent (blank_split); DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p", blank_split, blank_trans, pending_trans); info->default_account = *xaccAccountGetGUID (default_account); // gnc_table_leave_update (table, table->current_cursor_loc); multi_line = (reg->style == REG_STYLE_JOURNAL); dynamic = (reg->style == REG_STYLE_AUTO_LEDGER); lead_cursor = gnc_split_register_get_passive_cursor (reg); split_cursor = gnc_table_layout_get_cursor (table->layout, CURSOR_SPLIT); /* figure out where we are going to. */ if (info->traverse_to_new) { find_trans = blank_trans; find_split = NULL; find_trans_split = blank_split; find_class = CURSOR_CLASS_SPLIT; } else { find_trans = info->cursor_hint_trans; find_split = info->cursor_hint_split; find_trans_split = info->cursor_hint_trans_split; find_class = info->cursor_hint_cursor_class; } save_loc = table->current_cursor_loc; /* If the current cursor has changed we save the values for later * possible restoration. */ if (gnc_table_current_cursor_changed (table, TRUE) && (find_split == gnc_split_register_get_current_split (reg))) { cursor_buffer = gnc_cursor_buffer_new (); gnc_table_save_current_cursor (table, cursor_buffer); } else cursor_buffer = NULL; /* disable move callback -- we don't want the cascade of * callbacks while we are fiddling with loading the register */ gnc_table_control_allow_move (table->control, FALSE); /* invalidate the cursor */ { VirtualLocation virt_loc; gnc_virtual_location_init(&virt_loc); gnc_table_move_cursor_gui (table, virt_loc); } /* make sure that the header is loaded */ vcell_loc.virt_row = 0; vcell_loc.virt_col = 0; cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER); gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc); vcell_loc.virt_row++; /* get the current time and reset the dividing row */ present = gnc_time64_get_today_end (); if (use_autoreadonly) { GDate *d = qof_book_get_autoreadonly_gdate(gnc_get_current_book()); // "d" is NULL if use_autoreadonly is FALSE autoreadonly_time = d ? timespecToTime64(gdate_to_timespec(*d)) : 0; g_date_free(d); } if (info->first_pass) { if (default_account) { const char *last_num = xaccAccountGetLastNum (default_account); if (last_num) { NumCell *cell; cell = (NumCell *) gnc_table_layout_get_cell(table->layout, NUM_CELL); gnc_num_cell_set_last_num (cell, last_num); has_last_num = TRUE; } } /* load up account names into the transfer combobox menus */ gnc_split_register_load_xfer_cells (reg, default_account); gnc_split_register_load_recn_cells (reg); gnc_split_register_load_type_cells (reg); } if (info->separator_changed) change_account_separator (info, table, reg); table->model->dividing_row_upper = -1; table->model->dividing_row = -1; // Ensure that the transaction and splits being edited are in the split // list we're about to load. if (pending_trans != NULL) { for (node = xaccTransGetSplitList(pending_trans); node; node = node->next) { Split *pending_split = (Split*)node->data; if (!xaccTransStillHasSplit(pending_trans, pending_split)) continue; if (g_list_find(slist, pending_split) != NULL) continue; if (g_list_find_custom(slist, pending_trans, _find_split_with_parent_txn) != NULL) continue; if (!we_own_slist) { // lazy-copy slist = g_list_copy(slist); we_own_slist = TRUE; } slist = g_list_append(slist, pending_split); } } if (multi_line) trans_table = g_hash_table_new (g_direct_hash, g_direct_equal); /* populate the table */ for (node = slist; node; node = node->next) { split = node->data; trans = xaccSplitGetParent (split); if (!xaccTransStillHasSplit(trans, split)) continue; if (pending_trans == trans) found_pending = TRUE; /* If the transaction has only one split, and it's not our * pending_trans, then it's another register's blank split and * we don't want to see it. */ else if (xaccTransCountSplits (trans) == 1 && xaccSplitGetAccount (split) == NULL) continue; /* Do not load splits from the blank transaction. */ if (trans == blank_trans) continue; if (multi_line) { /* Skip this split if its transaction has already been loaded. */ if (g_hash_table_lookup (trans_table, trans)) continue; g_hash_table_insert (trans_table, trans, trans); } if (info->show_present_divider && use_autoreadonly && !found_divider_upper) { if (xaccTransGetDate (trans) >= autoreadonly_time) { table->model->dividing_row_upper = vcell_loc.virt_row; found_divider_upper = TRUE; } else { need_divider_upper = TRUE; } } if (info->show_present_divider && !found_divider && (xaccTransGetDate (trans) > present)) { table->model->dividing_row = vcell_loc.virt_row; found_divider = TRUE; } /* If this is the first load of the register, * fill up the quickfill cells. */ if (info->first_pass) add_quickfill_completions(reg->table->layout, trans, split, has_last_num); if (trans == find_trans) new_trans_row = vcell_loc.virt_row; if (split == find_trans_split) new_trans_split_row = vcell_loc.virt_row; gnc_split_register_add_transaction (reg, trans, split, lead_cursor, split_cursor, multi_line, start_primary_color, TRUE, find_trans, find_split, find_class, &new_split_row, &vcell_loc); if (!multi_line) start_primary_color = !start_primary_color; } if (multi_line) g_hash_table_destroy (trans_table); /* add the blank split at the end. */ if (pending_trans == blank_trans) found_pending = TRUE; /* No upper divider yet? Store it now */ if (info->show_present_divider && use_autoreadonly && !found_divider_upper && need_divider_upper) { table->model->dividing_row_upper = vcell_loc.virt_row; found_divider_upper = TRUE; } if (blank_trans == find_trans) new_trans_row = vcell_loc.virt_row; if (blank_split == find_trans_split) new_trans_split_row = vcell_loc.virt_row; /* If we didn't find the pending transaction, it was removed * from the account. */ if (!found_pending) { info->pending_trans_guid = *guid_null (); if (xaccTransIsOpen (pending_trans)) xaccTransCommitEdit (pending_trans); else if (pending_trans) g_assert_not_reached(); pending_trans = NULL; } /* go to blank on first pass */ if (info->first_pass) { new_split_row = -1; new_trans_split_row = -1; new_trans_row = -1; save_loc.vcell_loc = vcell_loc; save_loc.phys_row_offset = 0; save_loc.phys_col_offset = 0; } gnc_split_register_add_transaction (reg, blank_trans, blank_split, lead_cursor, split_cursor, multi_line, start_primary_color, info->blank_split_edited, find_trans, find_split, find_class, &new_split_row, &vcell_loc); /* resize the table to the sizes we just counted above */ /* num_virt_cols is always one. */ gnc_table_set_size (table, vcell_loc.virt_row, 1); /* restore the cursor to its rightful position */ { VirtualLocation trans_split_loc; if (new_split_row > 0) save_loc.vcell_loc.virt_row = new_split_row; else if (new_trans_split_row > 0) save_loc.vcell_loc.virt_row = new_trans_split_row; else if (new_trans_row > 0) save_loc.vcell_loc.virt_row = new_trans_row; trans_split_loc = save_loc; gnc_split_register_get_trans_split (reg, save_loc.vcell_loc, &trans_split_loc.vcell_loc); if (dynamic || multi_line || info->trans_expanded) { gnc_table_set_virt_cell_cursor( table, trans_split_loc.vcell_loc, gnc_split_register_get_active_cursor (reg)); gnc_split_register_set_trans_visible (reg, trans_split_loc.vcell_loc, TRUE, multi_line); info->trans_expanded = (reg->style == REG_STYLE_LEDGER); } else { save_loc = trans_split_loc; info->trans_expanded = FALSE; } if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE)) { gnc_table_move_cursor_gui (table, save_loc); new_split_row = save_loc.vcell_loc.virt_row; if (find_split == gnc_split_register_get_current_split (reg)) gnc_table_restore_current_cursor (table, cursor_buffer); } } gnc_cursor_buffer_destroy (cursor_buffer); cursor_buffer = NULL; update_info (info, reg); gnc_split_register_set_cell_fractions( reg, gnc_split_register_get_current_split (reg)); gnc_table_refresh_gui (table, TRUE); gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc); /* enable callback for cursor user-driven moves */ gnc_table_control_allow_move (table->control, TRUE); if (we_own_slist) g_list_free(slist); LEAVE(" "); }
/** 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 gboolean save_transaction( GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits ) { const GncGUID* guid; gint op; gboolean is_infant; QofInstance* inst; gboolean is_ok = TRUE; gchar* err = NULL; g_return_val_if_fail( be != NULL, FALSE ); g_return_val_if_fail( pTx != NULL, FALSE ); inst = QOF_INSTANCE(pTx); is_infant = qof_instance_get_infant( inst ); if ( qof_instance_get_destroying( inst ) ) { op = OP_DB_DELETE; } else if ( be->is_pristine_db || is_infant ) { op = OP_DB_INSERT; } else { op = OP_DB_UPDATE; } if ( op != OP_DB_DELETE ) { gnc_commodity *commodity = xaccTransGetCurrency( pTx ); // Ensure the commodity is in the db is_ok = gnc_sql_save_commodity( be, commodity ); if ( ! is_ok ) { err = "Commodity save failed: Probably an invalid or missing currency"; qof_backend_set_error( &be->be, ERR_BACKEND_DATA_CORRUPT); } } if ( is_ok ) { is_ok = gnc_sql_do_db_operation( be, op, TRANSACTION_TABLE, GNC_ID_TRANS, pTx, tx_col_table ); if ( ! is_ok ) { err = "Transaction header save failed. Check trace log for SQL errors"; } } if ( is_ok ) { // Commit slots and splits guid = qof_instance_get_guid( inst ); if ( !qof_instance_get_destroying(inst) ) { is_ok = gnc_sql_slots_save( be, guid, is_infant, qof_instance_get_slots( inst ) ); if ( ! is_ok ) { err = "Slots save failed. Check trace log for SQL errors"; } if ( is_ok && do_save_splits ) { is_ok = save_splits( be, guid, xaccTransGetSplitList( pTx ) ); if ( ! is_ok ) { err = "Split save failed. Check trace log for SQL errors"; } } } else { is_ok = gnc_sql_slots_delete( be, guid ); if ( ! is_ok ) { err = "Slots delete failed. Check trace log for SQL errors"; } if ( is_ok ) { is_ok = delete_splits( be, pTx ); if ( ! is_ok ) { err = "Split delete failed. Check trace log for SQL errors"; } } } } if (! is_ok ) { G_GNUC_UNUSED gchar *message1 = "Transaction %s dated %s in account %s not saved due to %s.%s"; G_GNUC_UNUSED gchar *message2 = "\nDatabase may be corrupted, check your data carefully."; Split* split = xaccTransGetSplit( pTx, 0); Account *acc = xaccSplitGetAccount( split ); /* FIXME: This needs to be implemented qof_error_format_secondary_text( GTK_MESSAGE_DIALOG( msg ), message1, xaccTransGetDescription( pTx ), qof_print_date( xaccTransGetDate( pTx ) ), xaccAccountGetName( acc ), err, message2 ); */ PERR( "Transaction %s dated %s in account %s not saved due to %s.\n", xaccTransGetDescription( pTx ), qof_print_date( xaccTransGetDate( pTx ) ), xaccAccountGetName( acc ), err ); } return is_ok; }
GtkWidget * gnc_reconcile_view_new (Account *account, GNCReconcileViewType type, time64 statement_date) { GNCReconcileView *view; GtkListStore *liststore; gboolean include_children, auto_check; GList *accounts = NULL; GList *splits; Query *query; g_return_val_if_fail (account, NULL); g_return_val_if_fail ((type == RECLIST_DEBIT) || (type == RECLIST_CREDIT), NULL); view = g_object_new (GNC_TYPE_RECONCILE_VIEW, NULL); /* Create the list store with 6 columns and add to treeview, column 0 will be a pointer to the entry */ liststore = gtk_list_store_new (6, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN ); gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL (liststore)); g_object_unref (liststore); view->account = account; view->view_type = type; view->statement_date = statement_date; query = qof_query_create_for (GNC_ID_SPLIT); qof_query_set_book (query, gnc_get_current_book ()); include_children = xaccAccountGetReconcileChildrenStatus (account); if (include_children) accounts = gnc_account_get_descendants (account); /* match the account */ accounts = g_list_prepend (accounts, account); xaccQueryAddAccountMatch (query, accounts, QOF_GUID_MATCH_ANY, QOF_QUERY_AND); g_list_free (accounts); /* limit the matches to CREDITs and DEBITs only, depending on the type */ if (type == RECLIST_CREDIT) xaccQueryAddValueMatch(query, gnc_numeric_zero (), QOF_NUMERIC_MATCH_CREDIT, QOF_COMPARE_GTE, QOF_QUERY_AND); else xaccQueryAddValueMatch(query, gnc_numeric_zero (), QOF_NUMERIC_MATCH_DEBIT, QOF_COMPARE_GTE, QOF_QUERY_AND); /* limit the matches only to Cleared and Non-reconciled splits */ xaccQueryAddClearedMatch (query, CLEARED_NO | CLEARED_CLEARED, QOF_QUERY_AND); /* Initialize the QueryList */ gnc_reconcile_view_construct (view, query); /* find the list of splits to auto-reconcile */ auto_check = gnc_prefs_get_bool (GNC_PREFS_GROUP_RECONCILE, GNC_PREF_CHECK_CLEARED); if (auto_check) { time64 statement_date_day_end = gnc_time64_get_day_end(statement_date); for (splits = qof_query_run (query); splits; splits = splits->next) { Split *split = splits->data; char recn = xaccSplitGetReconcile (split); time64 trans_date = xaccTransGetDate (xaccSplitGetParent (split)); /* Just an extra verification that our query is correct ;) */ g_assert (recn == NREC || recn == CREC); if (recn == CREC && gnc_difftime (trans_date, statement_date_day_end) <= 0) g_hash_table_insert (view->reconciled, split, split); } } /* Free the query -- we don't need it anymore */ qof_query_destroy (query); return GTK_WIDGET (view); }
static gint sxftd_init( SXFromTransInfo *sxfti ) { GtkWidget *w; const char *transName; gint pos; GList *schedule = NULL; time_t start_tt; struct tm *tmpTm; GDate date, nextDate; if ( ! sxfti->sx ) { return -1; } if ( ! sxfti->trans ) { return -2; } if ( xaccTransIsOpen( sxfti->trans ) ) { return SXFTD_ERRNO_OPEN_XACTION; } sxfti_attach_callbacks(sxfti); /* Setup the example calendar and related data structures. */ { int num_marks = SXFTD_EXCAL_NUM_MONTHS * 31; w = GTK_WIDGET(glade_xml_get_widget( sxfti->gxml, SXFTD_EX_CAL_FRAME )); sxfti->dense_cal_model = gnc_dense_cal_store_new(num_marks); sxfti->example_cal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(sxfti->dense_cal_model))); g_object_ref_sink(sxfti->example_cal); g_assert(sxfti->example_cal); gnc_dense_cal_set_num_months( sxfti->example_cal, SXFTD_EXCAL_NUM_MONTHS ); gnc_dense_cal_set_months_per_col( sxfti->example_cal, SXFTD_EXCAL_MONTHS_PER_COL ); gtk_container_add( GTK_CONTAINER(w), GTK_WIDGET(sxfti->example_cal) ); } /* Setup the start and end dates as GNCDateEdits */ { GtkWidget *paramTable = glade_xml_get_widget( sxfti->gxml, SXFTD_PARAM_TABLE ); sxfti->startDateGDE = GNC_DATE_EDIT( gnc_date_edit_new( time( NULL ), FALSE, FALSE ) ); gtk_table_attach( GTK_TABLE(paramTable), GTK_WIDGET( sxfti->startDateGDE ), 1, 2, 2, 3, (GTK_EXPAND | GTK_FILL), GTK_FILL, 0, 0 ); g_signal_connect( sxfti->startDateGDE, "date-changed", G_CALLBACK( sxftd_update_excal_adapt ), sxfti ); } { GtkWidget *endDateBox = glade_xml_get_widget( sxfti->gxml, SXFTD_END_DATE_BOX ); sxfti->endDateGDE = GNC_DATE_EDIT( gnc_date_edit_new( time( NULL ), FALSE, FALSE ) ); gtk_box_pack_start( GTK_BOX( endDateBox ), GTK_WIDGET( sxfti->endDateGDE ), FALSE, TRUE, 0 ); g_signal_connect( sxfti->endDateGDE, "date-changed", G_CALLBACK( sxftd_update_excal_adapt ), sxfti ); } /* Get the name from the transaction, try that as the initial SX name. */ transName = xaccTransGetDescription( sxfti->trans ); xaccSchedXactionSetName( sxfti->sx, transName ); /* Setup the initial start date for user display/confirmation */ /* compute good initial date. */ start_tt = xaccTransGetDate( sxfti->trans ); g_date_set_time_t( &date, start_tt ); w = glade_xml_get_widget(sxfti->gxml, SXFTD_FREQ_COMBO_BOX); gtk_combo_box_set_active(GTK_COMBO_BOX(w), 0); g_signal_connect( w, "changed", G_CALLBACK(sxftd_freq_combo_changed), sxfti ); sxftd_update_schedule( sxfti, &date, &schedule); recurrenceListNextInstance(schedule, &date, &nextDate); recurrenceListFree(&schedule); tmpTm = g_new0( struct tm, 1 ); g_date_to_struct_tm( &nextDate, tmpTm ); start_tt = mktime( tmpTm ); g_free( tmpTm ); gnc_date_edit_set_time( sxfti->startDateGDE, start_tt ); w = glade_xml_get_widget( sxfti->gxml, SXFTD_NAME_ENTRY ); pos = 0; gtk_editable_insert_text( GTK_EDITABLE(w), transName, (strlen(transName) * sizeof(char)), &pos ); g_signal_connect( GTK_OBJECT(w), "destroy", G_CALLBACK(sxftd_destroy), sxfti ); sxftd_update_example_cal( sxfti ); return 0; }
/******************************************************* * account_splits * * gather the splits / transactions for an account and * send them to a file *******************************************************/ static void account_splits (CsvExportInfo *info, Account *acc, FILE *fh ) { Query *q; GSList *p1, *p2; GList *splits; QofBook *book; gchar *end_sep; gchar *mid_sep; q = qof_query_create_for(GNC_ID_SPLIT); book = gnc_get_current_book(); qof_query_set_book (q, book); /* Set up separators */ if (info->use_quotes) { end_sep = "\""; mid_sep = g_strconcat ( "\"", info->separator_str, "\"", NULL); } else { end_sep = ""; mid_sep = g_strconcat ( info->separator_str, NULL); } /* Sort by transaction date */ p1 = g_slist_prepend (NULL, TRANS_DATE_POSTED); p1 = g_slist_prepend (p1, SPLIT_TRANS); p2 = g_slist_prepend (NULL, QUERY_DEFAULT_SORT); qof_query_set_sort_order (q, p1, p2, NULL); xaccQueryAddSingleAccountMatch (q, acc, QOF_QUERY_AND); xaccQueryAddDateMatchTT (q, TRUE, info->csvd.start_time, TRUE, info->csvd.end_time, QOF_QUERY_AND); /* Run the query */ for (splits = qof_query_run(q); splits; splits = splits->next) { Split *split; Transaction *trans; SplitList *s_list; GList *node; Split *t_split; int nSplits; int cnt; gchar *part1; gchar *part2; gchar *date; const gchar *currentSel; const gchar *split_amount; split = splits->data; trans = xaccSplitGetParent(split); nSplits = xaccTransCountSplits(trans); s_list = xaccTransGetSplitList(trans); /* Date */ date = qof_print_date ( xaccTransGetDate(trans)); part1 = g_strconcat ( end_sep, date, mid_sep, NULL); g_free(date); /* Name */ currentSel = xaccAccountGetName(acc); part2 = g_strconcat ( part1, currentSel, mid_sep, NULL); g_free(part1); /* Number */ currentSel = gnc_get_num_action(trans, NULL); part1 = g_strconcat ( part2, currentSel, mid_sep, NULL); g_free(part2); /* Description */ currentSel = xaccTransGetDescription(trans); part2 = g_strconcat ( part1, currentSel, mid_sep, NULL); g_free(part1); /* Notes */ currentSel = xaccTransGetNotes(trans); if (currentSel == NULL) part1 = g_strconcat ( part2, mid_sep, NULL); else part1 = g_strconcat ( part2, currentSel, mid_sep, NULL); g_free(part2); /* Memo */ currentSel = xaccSplitGetMemo(split); part2 = g_strconcat ( part1, currentSel, mid_sep, NULL); g_free(part1); /* Category */ currentSel = xaccSplitGetCorrAccountName(split); part1 = g_strconcat ( part2, currentSel, mid_sep, "T", mid_sep, NULL); g_free(part2); /* Action */ currentSel = gnc_get_num_action(NULL, split); part2 = g_strconcat ( part1, currentSel, mid_sep, NULL); g_free(part1); /* Reconcile */ switch (xaccSplitGetReconcile (split)) { case NREC: currentSel = "N"; break; case CREC: currentSel = "C"; break; case YREC: currentSel = "Y"; break; case FREC: currentSel = "F"; break; case VREC: currentSel = "V"; break; default: currentSel = "N"; } part1 = g_strconcat ( part2, currentSel, mid_sep, NULL); g_free(part2); /* To with Symbol */ split_amount = xaccPrintAmount(xaccSplitGetAmount(split), gnc_split_amount_print_info(split, TRUE)); part2 = g_strconcat ( part1, split_amount, mid_sep, NULL); g_free(part1); /* From with Symbol */ part1 = g_strconcat ( part2, "", mid_sep, NULL); g_free(part2); /* To Number Only */ split_amount = xaccPrintAmount(xaccSplitGetAmount(split), gnc_split_amount_print_info(split, FALSE)); part2 = g_strconcat ( part1, split_amount, mid_sep, NULL); g_free(part1); /* From Number Only */ part1 = g_strconcat ( part2, "", mid_sep, "", mid_sep, "", end_sep, "\n", NULL); g_free(part2); /* Write to file */ if (!write_line_to_file(fh, part1)) { info->failed = TRUE; break; } g_free(part1); /* Loop through the list of splits for the Transcation */ node = s_list; cnt = 0; while ( (cnt < nSplits) && (info->failed == FALSE)) { t_split = node->data; /* Start of line */ part1 = g_strconcat ( end_sep, mid_sep, mid_sep, mid_sep, mid_sep, mid_sep, NULL); /* Memo */ currentSel = xaccSplitGetMemo(t_split); part2 = g_strconcat ( part1, currentSel, mid_sep, NULL); g_free(part1); /* Account */ currentSel = xaccAccountGetName( xaccSplitGetAccount(t_split)); part1 = g_strconcat ( part2, currentSel, mid_sep, "S", mid_sep, NULL); g_free(part2); /* Action */ currentSel = gnc_get_num_action(NULL, t_split); part2 = g_strconcat ( part1, currentSel, mid_sep, NULL); g_free(part1); /* Reconcile */ switch (xaccSplitGetReconcile (split)) { case NREC: currentSel = "N"; break; case CREC: currentSel = "C"; break; case YREC: currentSel = "Y"; break; case FREC: currentSel = "F"; break; case VREC: currentSel = "V"; break; default: currentSel = "N"; } part1 = g_strconcat ( part2, currentSel, mid_sep, NULL); g_free(part2); /* From / To with Symbol */ split_amount = xaccPrintAmount(xaccSplitGetAmount(t_split), gnc_split_amount_print_info(t_split, TRUE)); if (xaccSplitGetAccount(t_split) == acc) part2 = g_strconcat ( part1, split_amount, mid_sep, mid_sep, NULL); else part2 = g_strconcat ( part1, mid_sep, split_amount, mid_sep, NULL); g_free(part1); /* From / To Numbers only */ split_amount = xaccPrintAmount(xaccSplitGetAmount(t_split), gnc_split_amount_print_info(t_split, FALSE)); if (xaccSplitGetAccount(t_split) == acc) part1 = g_strconcat ( part2, split_amount, mid_sep, mid_sep, NULL); else part1 = g_strconcat ( part2, mid_sep, split_amount, mid_sep, NULL); g_free(part2); /* From / To - Share Price / Conversion factor */ split_amount = xaccPrintAmount(xaccSplitGetSharePrice(t_split), gnc_split_amount_print_info(t_split, FALSE)); if (xaccSplitGetAccount(t_split) == acc) part2 = g_strconcat ( part1, split_amount, mid_sep, end_sep, "\n", NULL); else part2 = g_strconcat ( part1, mid_sep, split_amount, end_sep, "\n", NULL); g_free(part1); if (!write_line_to_file(fh, part2)) info->failed = TRUE; g_free(part2); cnt++; node = node->next; } } g_free(mid_sep); qof_query_destroy (q); g_list_free( splits ); }
static void downloaded_transaction_append(GNCImportMatchPicker * matcher, GNCImportTransInfo * transaction_info) { GtkListStore *store; GtkTreeIter iter; GtkTreeSelection *selection; Transaction *trans; Split *split; gchar *text; const gchar *ro_text; gboolean found = FALSE; GNCImportTransInfo *local_info; g_assert(matcher); g_assert(transaction_info); /*DEBUG("Begin");*/ /* Has the transaction already been added? */ store = GTK_LIST_STORE(gtk_tree_view_get_model(matcher->downloaded_view)); if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { do { gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DOWNLOADED_COL_INFO_PTR, &local_info, -1); if (local_info == transaction_info) { found = TRUE; break; } } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)); } if (!found) gtk_list_store_append(store, &iter); split = gnc_import_TransInfo_get_fsplit(transaction_info); trans = gnc_import_TransInfo_get_trans(transaction_info); /*Account*/ ro_text = xaccAccountGetName(xaccSplitGetAccount(split)); gtk_list_store_set(store, &iter, DOWNLOADED_COL_ACCOUNT, ro_text, -1); /*Date*/ text = qof_print_date(xaccTransGetDate(trans)); gtk_list_store_set(store, &iter, DOWNLOADED_COL_DATE, text, -1); g_free(text); /*Amount*/ ro_text = xaccPrintAmount(xaccSplitGetAmount(split), gnc_split_amount_print_info(split, TRUE)); gtk_list_store_set(store, &iter, DOWNLOADED_COL_AMOUNT, ro_text, -1); /*Description*/ ro_text = xaccTransGetDescription(trans); gtk_list_store_set(store, &iter, DOWNLOADED_COL_DESCRIPTION, ro_text, -1); /*Memo*/ ro_text = xaccSplitGetMemo(split); gtk_list_store_set(store, &iter, DOWNLOADED_COL_MEMO, ro_text, -1); /*Imbalance*/ /* Assume that the importer won't create a transaction that involves two or more currencies and no non-currency commodity. In that case can use the simpler value imbalance check. */ ro_text = xaccPrintAmount(xaccTransGetImbalanceValue(trans), gnc_default_print_info(TRUE)); gtk_list_store_set(store, &iter, DOWNLOADED_COL_BALANCED, ro_text, -1); gtk_list_store_set(store, &iter, DOWNLOADED_COL_INFO_PTR, transaction_info, -1); selection = gtk_tree_view_get_selection(matcher->downloaded_view); gtk_tree_selection_select_iter(selection, &iter); }
static void downloaded_transaction_changed_cb (GtkTreeSelection *selection, GNCImportMatchPicker *matcher) { GNCImportMatchInfo * match_info; GtkTreeModel *dl_model; GtkListStore *match_store; GtkTreeIter iter; GList * list_element; gchar *text; const gchar *ro_text; /*DEBUG("row: %d%s%d",row,", column: ",column);*/ /* Get the transaction info from the "downloaded" model. */ if (!gtk_tree_selection_get_selected(selection, &dl_model, &iter)) { matcher->selected_trans_info = NULL; return; } gtk_tree_model_get(dl_model, &iter, DOWNLOADED_COL_INFO_PTR, &matcher->selected_trans_info, -1); /* Now rewrite the "match" model based on that trans. */ match_store = GTK_LIST_STORE(gtk_tree_view_get_model(matcher->match_view)); gtk_list_store_clear(match_store); list_element = g_list_first (gnc_import_TransInfo_get_match_list (matcher->selected_trans_info)); while (list_element != NULL) { match_info = list_element->data; gtk_list_store_append(match_store, &iter); /* Print fields. */ /* Probability */ text = g_strdup_printf("%d", gnc_import_MatchInfo_get_probability (match_info)); gtk_list_store_set(match_store, &iter, MATCHER_COL_CONFIDENCE, text, -1); g_free(text); /* Date */ text = qof_print_date ( xaccTransGetDate ( xaccSplitGetParent ( gnc_import_MatchInfo_get_split(match_info) ) )); gtk_list_store_set(match_store, &iter, MATCHER_COL_DATE, text, -1); g_free(text); /* Amount */ ro_text = xaccPrintAmount( xaccSplitGetAmount ( gnc_import_MatchInfo_get_split(match_info) ), gnc_split_amount_print_info(gnc_import_MatchInfo_get_split(match_info), TRUE) ); gtk_list_store_set(match_store, &iter, MATCHER_COL_AMOUNT, ro_text, -1); /*Description*/ ro_text = xaccTransGetDescription ( xaccSplitGetParent( gnc_import_MatchInfo_get_split(match_info)) ); gtk_list_store_set(match_store, &iter, MATCHER_COL_DESCRIPTION, ro_text, -1); /*Split memo*/ ro_text = xaccSplitGetMemo(gnc_import_MatchInfo_get_split(match_info) ); gtk_list_store_set(match_store, &iter, MATCHER_COL_MEMO, ro_text, -1); gtk_list_store_set(match_store, &iter, MATCHER_COL_INFO_PTR, match_info, -1); if (gnc_import_MatchInfo_get_probability(match_info) != 0) { if (SHOW_NUMERIC_SCORE == TRUE) { gtk_list_store_set(match_store, &iter, MATCHER_COL_CONFIDENCE_PIXBUF, gen_probability_pixbuf(gnc_import_MatchInfo_get_probability(match_info), matcher->user_settings, GTK_WIDGET(matcher->match_view)), -1); } else { gtk_list_store_set(match_store, &iter, MATCHER_COL_CONFIDENCE_PIXBUF, gen_probability_pixbuf(gnc_import_MatchInfo_get_probability(match_info), matcher->user_settings, GTK_WIDGET(matcher->match_view)), -1); } } if (match_info == gnc_import_TransInfo_get_selected_match (matcher->selected_trans_info)) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(matcher->match_view); gtk_tree_selection_select_iter(selection, &iter); } list_element = g_list_next(list_element); } }
static void refresh_model_row (GNCImportMainMatcher *gui, GtkTreeModel *model, GtkTreeIter *iter, GNCImportTransInfo *info) { GtkListStore *store; GtkTreeSelection *selection; gchar *tmp, *imbalance, *text, *color; const gchar *ro_text; Split *split; g_assert (gui); g_assert (model); g_assert (info); /*DEBUG("Begin");*/ store = GTK_LIST_STORE(model); gtk_list_store_set(store, iter, DOWNLOADED_COL_DATA, info, -1); /*Account:*/ split = gnc_import_TransInfo_get_fsplit (info); g_assert(split); // Must not be NULL ro_text = xaccAccountGetName(xaccSplitGetAccount(split)); gtk_list_store_set(store, iter, DOWNLOADED_COL_ACCOUNT, ro_text, -1); /*Date*/ text = qof_print_date ( xaccTransGetDate( gnc_import_TransInfo_get_trans(info) ) ); gtk_list_store_set(store, iter, DOWNLOADED_COL_DATE, text, -1); g_free(text); /*Amount*/ ro_text = xaccPrintAmount (xaccSplitGetAmount (split), gnc_split_amount_print_info(split, TRUE) ); gtk_list_store_set(store, iter, DOWNLOADED_COL_AMOUNT, ro_text, -1); /*Description*/ ro_text = xaccTransGetDescription(gnc_import_TransInfo_get_trans(info) ); gtk_list_store_set(store, iter, DOWNLOADED_COL_DESCRIPTION, ro_text, -1); /*Memo*/ ro_text = xaccSplitGetMemo(split); gtk_list_store_set(store, iter, DOWNLOADED_COL_MEMO, ro_text, -1); /*Actions*/ /* Action informations */ ro_text = text = color = NULL; switch (gnc_import_TransInfo_get_action(info)) { case GNCImport_ADD: if (gnc_import_TransInfo_is_balanced(info) == TRUE) { ro_text = _("New, already balanced"); color = COLOR_GREEN; } else { /* Assume that importers won't create transactions in two or more currencies so we can use xaccTransGetImbalanceValue */ imbalance = g_strdup (xaccPrintAmount (gnc_numeric_neg(xaccTransGetImbalanceValue (gnc_import_TransInfo_get_trans(info) )), gnc_commodity_print_info (xaccTransGetCurrency(gnc_import_TransInfo_get_trans (info)), TRUE) )); if (gnc_import_TransInfo_get_destacc (info) != NULL) { color = COLOR_GREEN; tmp = gnc_account_get_full_name (gnc_import_TransInfo_get_destacc (info)); if (gnc_import_TransInfo_get_destacc_selected_manually(info) == TRUE) { text = /* Translators: %1$s is the amount to be transferred. %2$s is the destination account. */ g_strdup_printf(_("New, transfer %s to (manual) \"%s\""), imbalance, tmp); } else { text = /* Translators: %1$s is the amount to be transferred. %2$s is the destination account. */ g_strdup_printf(_("New, transfer %s to (auto) \"%s\""), imbalance, tmp); } g_free (tmp); } else { color = COLOR_YELLOW; text = /* Translators: %s is the amount to be transferred. */ g_strdup_printf(_("New, UNBALANCED (need acct to transfer %s)!"), imbalance); } g_free (imbalance); } break; case GNCImport_CLEAR: if (gnc_import_TransInfo_get_selected_match(info)) { color = COLOR_GREEN; if (gnc_import_TransInfo_get_match_selected_manually(info) == TRUE) { ro_text = _("Reconcile (manual) match"); } else { ro_text = _("Reconcile (auto) match"); } } else { color = COLOR_RED; ro_text = _("Match missing!"); } break; case GNCImport_UPDATE: if (gnc_import_TransInfo_get_selected_match(info)) { color = COLOR_GREEN; if (gnc_import_TransInfo_get_match_selected_manually(info) == TRUE) { ro_text = _("Update and reconcile (manual) match"); } else { ro_text = _("Update and reconcile (auto) match"); } } else { color = COLOR_RED; ro_text = _("Match missing!"); } break; case GNCImport_SKIP: color = COLOR_RED; ro_text = _("Do not import (no action selected)"); break; default: color = "white"; ro_text = "WRITEME, this is an unknown action"; break; } gtk_list_store_set(store, iter, DOWNLOADED_COL_COLOR, color, DOWNLOADED_COL_ACTION_INFO, ro_text ? ro_text : text, -1); if (text) g_free(text); /* Set the pixmaps */ gtk_list_store_set(store, iter, DOWNLOADED_COL_ACTION_ADD, gnc_import_TransInfo_get_action(info) == GNCImport_ADD, -1); if (gnc_import_TransInfo_get_action(info) == GNCImport_SKIP) { /*Show the best match's confidence pixmap in the info column*/ gtk_list_store_set(store, iter, DOWNLOADED_COL_ACTION_PIXBUF, gen_probability_pixbuf( gnc_import_MatchInfo_get_probability ( gnc_import_TransInfo_get_selected_match (info)), gui->user_settings, GTK_WIDGET(gui->view)), -1); } gtk_list_store_set(store, iter, DOWNLOADED_COL_ACTION_CLEAR, gnc_import_TransInfo_get_action(info) == GNCImport_CLEAR, -1); if (gnc_import_TransInfo_get_action(info) == GNCImport_CLEAR) { /*Show the best match's confidence pixmap in the info column*/ gtk_list_store_set(store, iter, DOWNLOADED_COL_ACTION_PIXBUF, gen_probability_pixbuf( gnc_import_MatchInfo_get_probability ( gnc_import_TransInfo_get_selected_match (info)), gui->user_settings, GTK_WIDGET(gui->view)), -1); } gtk_list_store_set(store, iter, DOWNLOADED_COL_ACTION_UPDATE, gnc_import_TransInfo_get_action(info) == GNCImport_UPDATE, -1); if (gnc_import_TransInfo_get_action(info) == GNCImport_UPDATE) { /*Show the best match's confidence pixmap in the info column*/ gtk_list_store_set(store, iter, DOWNLOADED_COL_ACTION_PIXBUF, gen_probability_pixbuf( gnc_import_MatchInfo_get_probability ( gnc_import_TransInfo_get_selected_match (info)), gui->user_settings, GTK_WIDGET(gui->view)), -1); } selection = gtk_tree_view_get_selection(gui->view); gtk_tree_selection_unselect_all(selection); }