Skip to content

Commit 2657f28

Browse files
authored
fix: YNAB import format import does not rely on fixed column order (#826)
1 parent c14b605 commit 2657f28

File tree

5 files changed

+21
-21
lines changed

5 files changed

+21
-21
lines changed

pkg/importer/parser/ynab-import/parse.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,18 @@ func Parse(f io.Reader, account models.Account) ([]importer.TransactionPreview,
2424

2525
var transactions []importer.TransactionPreview
2626

27-
// Skip the first line
28-
_, err := reader.Read()
27+
// First line contains headers
28+
headerRow, err := reader.Read()
2929
if err == io.EOF {
3030
return []importer.TransactionPreview{}, nil
3131
}
3232

33+
// Build map for header keys
34+
headers := map[string]int{}
35+
for i := range headerRow {
36+
headers[headerRow[i]] = i
37+
}
38+
3339
for {
3440
record, err := reader.Read()
3541
if err == io.EOF {
@@ -39,7 +45,7 @@ func Parse(f io.Reader, account models.Account) ([]importer.TransactionPreview,
3945
return csvReadError(reader, fmt.Errorf("could not read line in CSV: %w", err))
4046
}
4147

42-
date, err := time.Parse("01/02/2006", record[Date])
48+
date, err := time.Parse("01/02/2006", record[headers["Date"]])
4349
if err != nil {
4450
return csvReadError(reader, fmt.Errorf("could not parse time: %w", err))
4551
}
@@ -49,31 +55,31 @@ func Parse(f io.Reader, account models.Account) ([]importer.TransactionPreview,
4955
Date: date,
5056
AvailableFrom: types.NewMonth(date.Year(), date.Month()),
5157
ImportHash: helpers.Sha256String(strings.Join(record, ",")),
52-
Note: record[Memo],
58+
Note: record[headers["Memo"]],
5359
BudgetID: account.BudgetID,
5460
},
5561
}
5662

5763
// Set the source and destination account
58-
if record[Outflow] != "" && record[Inflow] != "" {
64+
if record[headers["Outflow"]] != "" && record[headers["Inflow"]] != "" {
5965
return csvReadError(reader, errors.New("both outflow and inflow are set for the transaction"))
60-
} else if record[Outflow] == "" && record[Inflow] == "" {
66+
} else if record[headers["Outflow"]] == "" && record[headers["Inflow"]] == "" {
6167
return csvReadError(reader, errors.New("no amount is set for the transaction"))
62-
} else if record[Outflow] != "" {
68+
} else if record[headers["Outflow"]] != "" {
6369
t.Transaction.SourceAccountID = account.DefaultModel.ID
64-
t.DestinationAccountName = record[Payee]
70+
t.DestinationAccountName = record[headers["Payee"]]
6571

66-
amount, err := decimal.NewFromString(record[Outflow])
72+
amount, err := decimal.NewFromString(record[headers["Outflow"]])
6773
if err != nil {
6874
return csvReadError(reader, errors.New("outflow could not be parsed to a decimal"))
6975
}
7076

7177
t.Transaction.Amount = amount
7278
} else {
7379
t.Transaction.DestinationAccountID = account.DefaultModel.ID
74-
t.SourceAccountName = record[Payee]
80+
t.SourceAccountName = record[headers["Payee"]]
7581

76-
amount, err := decimal.NewFromString(record[Inflow])
82+
amount, err := decimal.NewFromString(record[headers["Inflow"]])
7783
if err != nil {
7884
return csvReadError(reader, errors.New("inflow could not be parsed to a decimal"))
7985
}

pkg/importer/parser/ynab-import/parse_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func TestParse(t *testing.T) {
2020
}{
2121
{"Empty file", "empty.csv", 0},
2222
{"With content", "comdirect-ynap.csv", 3},
23+
{"With differently ordered content", "bank2ynab-ynap.csv", 1},
2324
}
2425

2526
for _, tt := range tests {

pkg/importer/parser/ynab-import/types.go

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Category,Payee,Date,Inflow,Outflow
2+
,exampleIssuer,11/06/2023,,82.8
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
Date,Payee,Memo,Outflow,Inflow
22
04/01/2019,,Test,59.97,
33
04/01/2019,,ISHSII-MSCI EUR.SRI EOACC WPKNR: A1H7ZS ISIN: IE00B52VJ196,119.98,
4-
04/01/2019,Leo Bernard,Lastschrift Sparplan 1,,180.00
4+
04/01/2019,Leo Bernard,Lastschrift Sparplan 1,,180.00

0 commit comments

Comments
 (0)