1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
package morrow
import (
"bufio"
"encoding/csv"
"fmt"
"io"
"strconv"
"strings"
"time"
"github.com/mpolden/journal/record"
)
// Reader implements a reader for Morrow-encoded (CSV) records.
type Reader struct {
rd io.Reader
}
// NewReader returns a new reader for Morrow-encoded records.
func NewReader(rd io.Reader) *Reader {
return &Reader{
rd: rd,
}
}
// Read all records from the underlying reader.
func (r *Reader) Read() ([]record.Record, error) {
buf := bufio.NewReader(r.rd)
c := csv.NewReader(buf)
c.FieldsPerRecord = -1 // Morrow export has an additional field which is not in the header
var rs []record.Record
line := 0
for {
csvRecord, err := c.Read()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
line++
if len(csvRecord) < 10 {
continue
}
if line == 1 {
continue // Skip header
}
t, err := time.Parse("02.01.2006", csvRecord[0])
if err != nil {
return nil, fmt.Errorf("invalid time on line %d: %q: %w", line, csvRecord[0], err)
}
amount, err := parseAmount(csvRecord[5])
if err != nil {
return nil, fmt.Errorf("invalid amount on line %d: %q: %w", line, amount, err)
}
text := strings.TrimSpace(csvRecord[2])
rs = append(rs, record.Record{Time: t, Text: text, Amount: amount})
}
return rs, nil
}
func parseAmount(s string) (int64, error) {
v := strings.ReplaceAll(s, ".", "")
n, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return 0, err
}
return n, nil
}
|