Browse Source

starting ofx and xml generators

master
Alexander Avery 3 years ago
parent
commit
3601f449c9
  1. 82
      generators.go
  2. 52
      main.go
  3. 19
      transactions.go

82
generators.go

@ -0,0 +1,82 @@
package main
import (
"encoding/xml"
"github.com/aclindsa/ofxgo"
"time"
"fmt"
"github.com/ochinchina/go-ini"
"io"
)
func transactionsFromXml(r io.Reader, assets ini.Section, vendors []ini.Key) ([]transaction, error) {
type xmlTransaction struct {
XMLName xml.Name `xml:"transaction"`
Date string `xml:"Date"`
TrnAmt float64 `xml:"amount"`
Asset string `xml:"Asset"`
Expense string `xml:"Expense,omitempty"`
VendorName string `xml:"VendorName,omitempty"`
Currency string `xml:"Currency"`
}
type transactionParent struct {
XMLName xml.Name `xml:"transactions"`
Transactions []xmlTransaction `xml:"transaction"`
}
root := new(transactionParent)
d := xml.NewDecoder(r)
err := d.Decode(&root)
if err != nil {
return nil, fmt.Errorf("failed unmarshaling xml: %w", err)
}
xtx := root.Transactions
transactions := make([]transaction, 0)
for _, t := range xtx {
var expense string
if t.VendorName != "" && t.Expense == "" {
expense = matchPartial(vendors, t.VendorName)
}
time, err := time.Parse("1/02/2006", t.Date)
if err != nil {
return nil, fmt.Errorf("failed parsing time: %w", err)
}
tx := transaction {
Date: time,
TrnAmt: t.TrnAmt,
Asset: t.Asset,
Expense: expense,
VendorName: t.VendorName,
Currency: t.Currency,
}
transactions = append(transactions, tx)
}
return transactions, nil
}
func transactionsFromOfx(r io.Reader, assets ini.Section, vendors []ini.Key) ([]transaction, error) {
resp, err := ofxgo.ParseResponse(r)
if err != nil {
return nil, err
}
transactions := make([]transaction, 0)
for _, m := range resp.Bank {
if stmt, ok := m.(*ofxgo.StatementResponse); ok {
for _, t := range stmt.BankTranList.Transactions {
acctId := stmt.BankAcctFrom.AcctID.String()
amt, _ := t.TrnAmt.Rat.Float64()
tx := transaction{
Date: t.DtPosted.Time,
TrnAmt: amt,
Asset: assets.GetValueWithDefault(acctId, acctId),
Expense: matchPartial(vendors, t.Name.String()),
VendorName: t.Name.String(),
Currency: stmt.CurDef.String(),
}
transactions = append(transactions, tx)
}
}
}
return transactions, nil
}

52
main.go

@ -1,19 +1,18 @@
package main
import (
"flag"
"os"
"bufio"
"flag"
"github.com/ochinchina/go-ini"
"io"
"log"
"os"
"sort"
"strings"
"io"
"text/template"
"sort"
"github.com/aclindsa/ofxgo"
"github.com/ochinchina/go-ini"
)
func matchVendor(keys []ini.Key, givenName string) string {
func matchPartial(keys []ini.Key, givenName string) string {
for _, k := range keys {
v := k.ValueWithDefault("")
if strings.Contains(givenName, k.Name()) {
@ -34,20 +33,24 @@ func generateLedgerTransactions(transactions []transaction, w io.Writer) error {
return nil
}
var (
config = flag.String("config", "", "configuration file containing all your vendor and account mappings")
inputType = flag.String("T", "ofx", "input type of transaction data - supports ofx and xml")
)
func main() {
var config = flag.String("config", "", "configuration file containing all your vendor and account mappings")
flag.Parse()
filename := flag.Arg(0)
r, err := os.Open(filename)
if err != nil {
log.Fatal(err)
log.Fatalf("failed opening data file: %w", err)
}
defer r.Close()
c, err := os.Open(*config)
if err != nil {
log.Fatal(err)
log.Fatalf("failed opening config file: %w", err)
}
defer c.Close()
@ -56,33 +59,24 @@ func main() {
assets, err := cfg.GetSection("Assets")
if err != nil {
log.Fatal(err)
log.Fatalf("failed finding assets section of config: %w", err)
}
vendors, err := cfg.GetSection("Vendors")
if err != nil {
log.Fatal(err)
log.Fatalf("failed finding vendors section of config: %w", err)
}
resp, err := ofxgo.ParseResponse(r)
var transactions []transaction
if *inputType == "ofx" {
transactions, err = transactionsFromOfx(r, *assets, vendors.Keys())
if err != nil {
log.Fatal(err)
}
transactions := make([]transaction, 0)
for _, m := range resp.Bank {
if stmt, ok := m.(*ofxgo.StatementResponse); ok {
for _, t := range stmt.BankTranList.Transactions {
acctId := stmt.BankAcctFrom.AcctID.String()
tx := transaction{
Date: t.DtPosted.Time,
TrnAmt: t.TrnAmt,
Asset: assets.GetValueWithDefault(acctId, acctId),
Vendor: matchVendor(vendors.Keys(), t.Name.String()),
VendorName: t.Name.String(),
}
transactions = append(transactions, tx)
log.Fatalf("failed generating transactions from ofx: %w", err)
}
} else if *inputType == "xml" {
transactions, err = transactionsFromXml(r, *assets, vendors.Keys())
if err != nil {
log.Fatalf("failed generating transactions from xml: %w", err)
}
}

19
transactions.go

@ -2,24 +2,23 @@ package main
import (
"time"
"github.com/aclindsa/ofxgo"
)
var transactionTemplate =
`
var transactionTemplate = `
{{ range . }}
{{ .Date.Format "2006-01-02" }} {{ .VendorName }}
{{ .Asset }} ${{ .TrnAmt }}
{{ .Vendor }}
{{ .Asset }} {{ .TrnAmt }} {{ .Currency }}
{{ .Expense }}
{{ end }}
`
type transaction struct {
Date time.Time
TrnAmt ofxgo.Amount
Asset string
Vendor string
VendorName string
Date time.Time `xml:"Date"`
TrnAmt float64 `xml:"Amount"`
Asset string `xml:"Asset"`
Expense string `xml:"Expense,omitempty"`
VendorName string `xml:"VendorName,omitempty"`
Currency string `xml:"Currency"`
}
type byDate []transaction

Loading…
Cancel
Save