CSV Import and Column Mapping#
The CSV import pipeline in Sure allows users to map arbitrary CSV columns from their bank exports to Sure's transaction fields. The primary entry point for generic CSV transaction imports is TransactionImport, a subclass of the polymorphic Import base class.
Canonical column keys for TransactionImport are date, amount, name, currency, category, tags, account, and notes — with date and amount required . Users configure which CSV header maps to each key during the setup workflow; these column label assignments are stored on the import record as date_col_label, amount_col_label, etc. .
Header Normalization and Aliases#
Before any column lookup, Sure normalizes every CSV header via normalize_header:
- Strip whitespace, lowercase
- Remove
*characters (used in Sure's own CSV template to mark required fields) - Replace spaces and hyphens with underscores
The normalized headers are cached in normalized_csv_headers, which also raises an error if two headers normalize to the same key (i.e., ambiguous column names).
Column lookups go through csv_value(row, label, *aliases), which tries the user-configured label first, then any built-in fallback aliases. For example, the amount field falls back to "balance", and the account field falls back to "account_name" . This allows many real-world bank CSV exports to "just work" without any manual column configuration.
Configurable import-level settings that affect parsing :
| Setting | Options |
|---|---|
col_sep | Comma (,) or Semicolon (;) |
number_format | 1,234.56 (US/UK), 1.234,56 (European), 1 234,56 (French/Scandinavian), 1,234 (zero-decimal) |
rows_to_skip | Integer — skips leading non-header rows |
date_format | Auto-detected via detect_date_format or user-selected |
signage_convention | inflows_positive or inflows_negative |
amount_type_strategy | signed_amount or custom_column (for banks that use separate debit/credit columns) |
The import also handles non-UTF-8 encodings automatically, using rchardet for detection and falling back through Windows-1250, Windows-1252, ISO-8859-1, and ISO-8859-2 . This covers most Central/Eastern European and Western European bank exports.
Previous import configuration reuse: suggested_template and apply_template! allow a new import to pre-fill its column/format configuration from the most recent completed import of the same type and account — useful for recurring bank exports.
Mapping Models#
After rows are generated, a sync step creates Import::Mapping records for each unique value in the mapped columns. Import::Mapping is the STI base class; the three concrete subclasses used by TransactionImport are:
Import::AccountMapping— maps CSV account name strings to existingAccountrecords, or creates a newDepositoryaccount on-the-fly . Selection is required: an unmapped account name raisesImport::MappingErrorat import time .Import::CategoryMapping— maps CSV category strings toCategoryrecords, supporting hierarchical QIF-style keys ("Home:Home Improvement"→ child"Home Improvement") . Selection is optional.Import::TagMapping— maps tag strings toTagrecords; creates new tags when marked creatable. Selection is optional.
The create_when_empty flag on each mapping record controls whether a missing mappable triggers auto-creation .
Tag Parsing#
Tags are parsed from a single CSV cell by Import::Row#tags_list. The delimiter is auto-detected: pipe (|) takes priority if an unescaped pipe is found, otherwise comma (,) is used. Backslash escaping allows tag names to contain delimiters .
Amount Sign Convention#
Import::Row#signed_amount handles the signage flip: Sure internally represents outflows as positive. With signed_amount strategy, the amount is negated when signage_convention is inflows_positive. With custom_column strategy, a separate entity-type column determines whether each row is an inflow or outflow .
Bank Format Compatibility#
Sure's CSV importer is designed to be flexible enough for most bank exports, but it does not natively parse proprietary binary/text formats:
- UBS (Switzerland) and similar non-standard CSVs — users in the community have noted that bank CSVs often have non-standard separators, headers, or separate debit/credit columns . The
custom_columnamount strategy, configurable separator, androws_to_skipsetting address most of these cases. - MT 940 (SWIFT Customer Statement) — a tag-based text format used widely by European banks. A feature request exists for native support; it is not currently implemented.
- CAMT.053 (ISO 20022 XML) — the XML successor to MT 940, now the standard for European business banking. A maintainer confirmed implementing both formats is feasible; native support does not exist yet . MT 940 was officially discontinued in 2025, making CAMT.053 the primary standard going forward.
For banks exporting in OFX format, the community-built sure-sync Docker tool provides an OFX-to-Sure ingestion pipeline with deduplication and account mapping outside of Sure's core import system .
Key Source Files#
| File | Purpose |
|---|---|
app/models/import.rb | Base class: CSV parsing, header normalization, number sanitization, date detection, template reuse |
app/models/transaction_import.rb | Generic CSV transaction importer; column keys, mapping steps, duplicate detection |
app/models/import/row.rb | Row model: tag parsing, date parsing, signed amount calculation |
app/models/import/mapping.rb | STI base class for all mapping types |
app/models/import/account_mapping.rb | Maps CSV account names → Account records |
app/models/import/category_mapping.rb | Maps CSV category strings → Category records (supports hierarchical keys) |
app/models/import/tag_mapping.rb | Maps CSV tag strings → Tag records |