mirror of
https://github.com/aclindsa/ofxgo.git
synced 2025-07-03 12:28:38 -04:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
d31ac10d08 | |||
4f2c5582d1 | |||
e302ce2e6b | |||
e3c4afc0a3 | |||
c2490e1c6a | |||
12aca9ab06 | |||
1f657a5d18 | |||
afd882f7d2 | |||
5ed0050aad | |||
09f161e13e | |||
e1a72fcd54 | |||
a4a166aa74 | |||
3ee400d1ec | |||
67fa945cc8 | |||
cb48d30deb | |||
12ea3b7e8b | |||
e76c697cad | |||
2641443ebe | |||
01b26887af | |||
2b8a79e4b7 | |||
9136c9bab2 | |||
0d93a42626 | |||
56ca46714b | |||
4c7c48cab7 | |||
8c1e6eafab | |||
52f3e4120b | |||
ef87cc536c | |||
830a6064c7 | |||
6807c93e0e | |||
10edd94920 | |||
d88d45a664 | |||
2caa23564a | |||
5923a34de0 | |||
aa4d8074b2 | |||
65cc26a0db | |||
8f3e7309f2 | |||
631508ccc9 | |||
60a5707de6 | |||
3240ef383b |
34
.github/workflows/test.yml
vendored
Normal file
34
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
name: ofxgo CI Test
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go-version: [1.13.x, 1.18.x, 1.20.x]
|
||||||
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go-version }}
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Test
|
||||||
|
run: go test -v -covermode=count -coverprofile="profile.cov" ./...
|
||||||
|
- name: Send Coverage
|
||||||
|
uses: shogo82148/actions-goveralls@v1
|
||||||
|
with:
|
||||||
|
path-to-profile: "profile.cov"
|
||||||
|
flag-name: ${{ matrix.os }}-go-${{ matrix.go-version }}
|
||||||
|
parallel: true
|
||||||
|
# notifies that all test jobs are finished.
|
||||||
|
finish:
|
||||||
|
needs: test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: shogo82148/actions-goveralls@v1
|
||||||
|
with:
|
||||||
|
parallel-finished: true
|
20
.travis.yml
20
.travis.yml
@ -1,20 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.9.x
|
|
||||||
- 1.12.x
|
|
||||||
- master
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
# Fetch/build coverage reporting tools
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
- go install github.com/mattn/goveralls
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go test -v -covermode=count -coverprofile=coverage.out
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken $COVERALLS_TOKEN
|
|
34
README.md
34
README.md
@ -1,9 +1,9 @@
|
|||||||
# OFXGo
|
# OFXGo
|
||||||
|
|
||||||
[](https://goreportcard.com/report/github.com/aclindsa/ofxgo)
|
[](https://goreportcard.com/report/github.com/aclindsa/ofxgo)
|
||||||
[](https://travis-ci.org/aclindsa/ofxgo)
|
[](https://github.com/aclindsa/ofxgo/actions?query=workflow%3A%22ofxgo+CI+Test%22+branch%3Amaster)
|
||||||
[](https://coveralls.io/github/aclindsa/ofxgo?branch=master)
|
[](https://coveralls.io/github/aclindsa/ofxgo?branch=master)
|
||||||
[](https://godoc.org/github.com/aclindsa/ofxgo)
|
[](https://pkg.go.dev/github.com/aclindsa/ofxgo)
|
||||||
|
|
||||||
**OFXGo** is a library for querying OFX servers and/or parsing the responses. It
|
**OFXGo** is a library for querying OFX servers and/or parsing the responses. It
|
||||||
also provides an example command-line client to demonstrate the use of the
|
also provides an example command-line client to demonstrate the use of the
|
||||||
@ -13,7 +13,7 @@ library.
|
|||||||
|
|
||||||
The main purpose of this project is to provide a library to make it easier to
|
The main purpose of this project is to provide a library to make it easier to
|
||||||
query financial information with OFX from the comfort of Golang, without having
|
query financial information with OFX from the comfort of Golang, without having
|
||||||
to marshal/unmarshal to SGML or XML. The library does *not* intend to abstract
|
to marshal/unmarshal to SGML or XML. The library does _not_ intend to abstract
|
||||||
away all of the details of the OFX specification, which would be difficult to do
|
away all of the details of the OFX specification, which would be difficult to do
|
||||||
well. Instead, it exposes the OFX SGML/XML hierarchy as structs which mostly
|
well. Instead, it exposes the OFX SGML/XML hierarchy as structs which mostly
|
||||||
resemble it. Its primary goal is to enable the creation of other personal
|
resemble it. Its primary goal is to enable the creation of other personal
|
||||||
@ -26,7 +26,8 @@ created a sample command-line client which uses the library to do simple tasks
|
|||||||
(currently it does little more than list accounts and query for balances and
|
(currently it does little more than list accounts and query for balances and
|
||||||
transactions). My hope is that by studying its code, new users will be able to
|
transactions). My hope is that by studying its code, new users will be able to
|
||||||
figure out how to use the library much faster than staring at the OFX
|
figure out how to use the library much faster than staring at the OFX
|
||||||
specification (or this library's API documentation). The command-line client
|
specification (or this library's [API
|
||||||
|
documentation](https://pkg.go.dev/github.com/aclindsa/ofxgo)). The command-line client
|
||||||
also serves as an easy way for me to test/debug the library with actual
|
also serves as an easy way for me to test/debug the library with actual
|
||||||
financial institutions, which frequently have 'quirks' in their implementations.
|
financial institutions, which frequently have 'quirks' in their implementations.
|
||||||
The command-line client can be found in the [cmd/ofx
|
The command-line client can be found in the [cmd/ofx
|
||||||
@ -36,7 +37,7 @@ repository.
|
|||||||
## Library documentation
|
## Library documentation
|
||||||
|
|
||||||
Documentation can be found with the `go doc` tool, or at
|
Documentation can be found with the `go doc` tool, or at
|
||||||
https://godoc.org/github.com/aclindsa/ofxgo
|
https://pkg.go.dev/github.com/aclindsa/ofxgo
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
@ -94,9 +95,30 @@ if stmt, ok := response.Bank[0].(*ofxgo.StatementResponse); ok {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Similarly, if you have an OFX file available locally, you can parse it directly:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
f, err := os.Open("./transactions.qfx")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("can't open file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
resp, err := ofxgo.ParseResponse(f)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("can't parse response: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// do something with resp (*ofxgo.Response)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
OFXGo requires go >= 1.9
|
OFXGo requires go >= 1.12
|
||||||
|
|
||||||
## Using the command-line client
|
## Using the command-line client
|
||||||
|
|
||||||
|
97
bank_test.go
97
bank_test.go
@ -284,3 +284,100 @@ func TestUnmarshalBankStatementResponse(t *testing.T) {
|
|||||||
checkResponsesEqual(t, &expected, response)
|
checkResponsesEqual(t, &expected, response)
|
||||||
checkResponseRoundTrip(t, response)
|
checkResponseRoundTrip(t, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPayeeValid(t *testing.T) {
|
||||||
|
p := Payee{
|
||||||
|
Name: "Jane",
|
||||||
|
Addr1: "Sesame Street",
|
||||||
|
City: "Mytown",
|
||||||
|
State: "AA",
|
||||||
|
PostalCode: "12345",
|
||||||
|
Phone: "12345678901",
|
||||||
|
}
|
||||||
|
valid, err := p.Valid()
|
||||||
|
if !valid {
|
||||||
|
t.Fatalf("Unexpected error from calling Valid: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure some empty fields trigger invalid response
|
||||||
|
badp := p
|
||||||
|
badp.Name = ""
|
||||||
|
valid, err = badp.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with empty name\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
badp = p
|
||||||
|
badp.Addr1 = ""
|
||||||
|
valid, err = badp.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with empty address\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
badp = p
|
||||||
|
badp.City = ""
|
||||||
|
valid, err = badp.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with empty city\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
badp = p
|
||||||
|
badp.State = ""
|
||||||
|
valid, err = badp.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with empty state\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
badp = p
|
||||||
|
badp.PostalCode = ""
|
||||||
|
valid, err = badp.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with empty postal code\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
badp = p
|
||||||
|
badp.Phone = ""
|
||||||
|
valid, err = badp.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with empty phone\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBalanceValid(t *testing.T) {
|
||||||
|
var a Amount
|
||||||
|
a.SetFrac64(8, 1)
|
||||||
|
b := Balance{
|
||||||
|
Name: "Checking",
|
||||||
|
Desc: "Jane's Personal Checking",
|
||||||
|
BalType: BalTypeDollar,
|
||||||
|
Value: a,
|
||||||
|
}
|
||||||
|
valid, err := b.Valid()
|
||||||
|
if !valid {
|
||||||
|
t.Fatalf("Unexpected error from calling Valid: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
badb := b
|
||||||
|
badb.Name = ""
|
||||||
|
valid, err = badb.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with empty name\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
badb = b
|
||||||
|
badb.Desc = ""
|
||||||
|
valid, err = badb.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with empty description\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
badb = Balance{
|
||||||
|
Name: "Checking",
|
||||||
|
Desc: "Jane's Personal Checking",
|
||||||
|
Value: a,
|
||||||
|
}
|
||||||
|
valid, err = badb.Valid()
|
||||||
|
if valid || err == nil {
|
||||||
|
t.Fatalf("Expected error from calling Valid with unspecified balance type\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,6 +21,8 @@ type BasicClient struct {
|
|||||||
NoIndent bool
|
NoIndent bool
|
||||||
// Use carriage returns on new lines
|
// Use carriage returns on new lines
|
||||||
CarriageReturn bool
|
CarriageReturn bool
|
||||||
|
// Set User-Agent header to this string, if not empty
|
||||||
|
UserAgent string
|
||||||
}
|
}
|
||||||
|
|
||||||
// OfxVersion returns the OFX specification version this BasicClient will marshal
|
// OfxVersion returns the OFX specification version this BasicClient will marshal
|
||||||
@ -61,27 +63,42 @@ func (c *BasicClient) CarriageReturnNewLines() bool {
|
|||||||
return c.CarriageReturn
|
return c.CarriageReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RawRequest is a convenience wrapper around http.Post. It is exposed only for
|
||||||
|
// when you need to read/inspect the raw HTTP response yourself.
|
||||||
func (c *BasicClient) RawRequest(URL string, r io.Reader) (*http.Response, error) {
|
func (c *BasicClient) RawRequest(URL string, r io.Reader) (*http.Response, error) {
|
||||||
if !strings.HasPrefix(URL, "https://") {
|
if !strings.HasPrefix(URL, "https://") {
|
||||||
return nil, errors.New("Refusing to send OFX request with possible plain-text password over non-https protocol")
|
return nil, errors.New("Refusing to send OFX request with possible plain-text password over non-https protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := http.Post(URL, "application/x-ofx", r)
|
request, err := http.NewRequest("POST", URL, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
request.Header.Set("Content-Type", "application/x-ofx")
|
||||||
|
request.Header.Add("Accept", "*/*, application/x-ofx")
|
||||||
|
if c.UserAgent != "" {
|
||||||
|
request.Header.Set("User-Agent", c.UserAgent)
|
||||||
|
}
|
||||||
|
response, err := http.DefaultClient.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if response.StatusCode != 200 {
|
if response.StatusCode != 200 {
|
||||||
return nil, errors.New("OFXQuery request status: " + response.Status)
|
return response, errors.New("OFXQuery request status: " + response.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestNoParse marshals a Request to XML, makes an HTTP request, and returns
|
||||||
|
// the raw HTTP response
|
||||||
func (c *BasicClient) RequestNoParse(r *Request) (*http.Response, error) {
|
func (c *BasicClient) RequestNoParse(r *Request) (*http.Response, error) {
|
||||||
return clientRequestNoParse(c, r)
|
return clientRequestNoParse(c, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request marshals a Request to XML, makes an HTTP request, and then
|
||||||
|
// unmarshals the response into a Response object.
|
||||||
func (c *BasicClient) Request(r *Request) (*Response, error) {
|
func (c *BasicClient) Request(r *Request) (*Response, error) {
|
||||||
return clientRequest(c, r)
|
return clientRequest(c, r)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ var filename, bankID, acctID, acctType string
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
defineServerFlags(downloadCommand.Flags)
|
defineServerFlags(downloadCommand.Flags)
|
||||||
downloadCommand.Flags.StringVar(&filename, "filename", "./download.ofx", "The file to save to")
|
downloadCommand.Flags.StringVar(&filename, "filename", "./response.ofx", "The file to save to")
|
||||||
downloadCommand.Flags.StringVar(&bankID, "bankid", "", "BankID (from `get-accounts` subcommand)")
|
downloadCommand.Flags.StringVar(&bankID, "bankid", "", "BankID (from `get-accounts` subcommand)")
|
||||||
downloadCommand.Flags.StringVar(&acctID, "acctid", "", "AcctID (from `get-accounts` subcommand)")
|
downloadCommand.Flags.StringVar(&acctID, "acctid", "", "AcctID (from `get-accounts` subcommand)")
|
||||||
downloadCommand.Flags.StringVar(&acctType, "accttype", "CHECKING", "AcctType (from `get-accounts` subcommand)")
|
downloadCommand.Flags.StringVar(&acctType, "accttype", "CHECKING", "AcctType (from `get-accounts` subcommand)")
|
||||||
@ -64,6 +64,11 @@ func download() {
|
|||||||
|
|
||||||
query.Bank = append(query.Bank, &statementRequest)
|
query.Bank = append(query.Bank, &statementRequest)
|
||||||
|
|
||||||
|
if dryrun {
|
||||||
|
printRequest(client, query)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response, err := client.RequestNoParse(query)
|
response, err := client.RequestNoParse(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error requesting account statement:", err)
|
fmt.Println("Error requesting account statement:", err)
|
||||||
|
@ -49,6 +49,11 @@ func bankTransactions() {
|
|||||||
|
|
||||||
query.Bank = append(query.Bank, &statementRequest)
|
query.Bank = append(query.Bank, &statementRequest)
|
||||||
|
|
||||||
|
if dryrun {
|
||||||
|
printRequest(client, query)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response, err := client.Request(query)
|
response, err := client.Request(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error requesting account statement:", err)
|
fmt.Println("Error requesting account statement:", err)
|
||||||
@ -77,7 +82,7 @@ func bankTransactions() {
|
|||||||
|
|
||||||
func printTransaction(defCurrency ofxgo.CurrSymbol, tran *ofxgo.Transaction) {
|
func printTransaction(defCurrency ofxgo.CurrSymbol, tran *ofxgo.Transaction) {
|
||||||
currency := defCurrency
|
currency := defCurrency
|
||||||
if ok, _ := tran.Currency.Valid(); ok {
|
if tran.Currency != nil {
|
||||||
currency = tran.Currency.CurSym
|
currency = tran.Currency.CurSym
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ var ccDownloadCommand = command{
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
defineServerFlags(ccDownloadCommand.Flags)
|
defineServerFlags(ccDownloadCommand.Flags)
|
||||||
ccDownloadCommand.Flags.StringVar(&filename, "filename", "./download.ofx", "The file to save to")
|
ccDownloadCommand.Flags.StringVar(&filename, "filename", "./response.ofx", "The file to save to")
|
||||||
ccDownloadCommand.Flags.StringVar(&acctID, "acctid", "", "AcctID (from `get-accounts` subcommand)")
|
ccDownloadCommand.Flags.StringVar(&acctID, "acctid", "", "AcctID (from `get-accounts` subcommand)")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +51,11 @@ func ccDownload() {
|
|||||||
}
|
}
|
||||||
query.CreditCard = append(query.CreditCard, &statementRequest)
|
query.CreditCard = append(query.CreditCard, &statementRequest)
|
||||||
|
|
||||||
|
if dryrun {
|
||||||
|
printRequest(client, query)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response, err := client.RequestNoParse(query)
|
response, err := client.RequestNoParse(query)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -38,6 +38,11 @@ func ccTransactions() {
|
|||||||
}
|
}
|
||||||
query.CreditCard = append(query.CreditCard, &statementRequest)
|
query.CreditCard = append(query.CreditCard, &statementRequest)
|
||||||
|
|
||||||
|
if dryrun {
|
||||||
|
printRequest(client, query)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response, err := client.Request(query)
|
response, err := client.Request(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error requesting account statement:", err)
|
fmt.Println("Error requesting account statement:", err)
|
||||||
@ -60,7 +65,7 @@ func ccTransactions() {
|
|||||||
fmt.Println("Transactions:")
|
fmt.Println("Transactions:")
|
||||||
for _, tran := range stmt.BankTranList.Transactions {
|
for _, tran := range stmt.BankTranList.Transactions {
|
||||||
currency := stmt.CurDef
|
currency := stmt.CurDef
|
||||||
if ok, _ := tran.Currency.Valid(); ok {
|
if tran.Currency != nil {
|
||||||
currency = tran.Currency.CurSym
|
currency = tran.Currency.CurSym
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/howeyc/gopass"
|
"golang.org/x/term"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type command struct {
|
type command struct {
|
||||||
@ -22,6 +23,9 @@ func (c *command) usage() {
|
|||||||
// flags common to all server transactions
|
// flags common to all server transactions
|
||||||
var serverURL, username, password, org, fid, appID, appVer, ofxVersion, clientUID string
|
var serverURL, username, password, org, fid, appID, appVer, ofxVersion, clientUID string
|
||||||
var noIndentRequests bool
|
var noIndentRequests bool
|
||||||
|
var carriageReturn bool
|
||||||
|
var dryrun bool
|
||||||
|
var userAgent string
|
||||||
|
|
||||||
func defineServerFlags(f *flag.FlagSet) {
|
func defineServerFlags(f *flag.FlagSet) {
|
||||||
f.StringVar(&serverURL, "url", "", "Financial institution's OFX Server URL (see ofxhome.com if you don't know it)")
|
f.StringVar(&serverURL, "url", "", "Financial institution's OFX Server URL (see ofxhome.com if you don't know it)")
|
||||||
@ -34,6 +38,9 @@ func defineServerFlags(f *flag.FlagSet) {
|
|||||||
f.StringVar(&ofxVersion, "ofxversion", "203", "OFX version to use")
|
f.StringVar(&ofxVersion, "ofxversion", "203", "OFX version to use")
|
||||||
f.StringVar(&clientUID, "clientuid", "", "Client UID (only required by a few FIs, like Chase)")
|
f.StringVar(&clientUID, "clientuid", "", "Client UID (only required by a few FIs, like Chase)")
|
||||||
f.BoolVar(&noIndentRequests, "noindent", false, "Don't indent OFX requests")
|
f.BoolVar(&noIndentRequests, "noindent", false, "Don't indent OFX requests")
|
||||||
|
f.BoolVar(&carriageReturn, "carriagereturn", false, "Use carriage return as line separator")
|
||||||
|
f.StringVar(&userAgent, "useragent", "", "Use string as User-Agent header when sending request")
|
||||||
|
f.BoolVar(&dryrun, "dryrun", false, "Don't send request - print content of request instead")
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkServerFlags() bool {
|
func checkServerFlags() bool {
|
||||||
@ -49,7 +56,7 @@ func checkServerFlags() bool {
|
|||||||
|
|
||||||
if ret && len(password) == 0 {
|
if ret && len(password) == 0 {
|
||||||
fmt.Printf("Password for %s: ", username)
|
fmt.Printf("Password for %s: ", username)
|
||||||
pass, err := gopass.GetPasswd()
|
pass, err := term.ReadPassword(int(os.Stdin.Fd()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error reading password: %s\n", err)
|
fmt.Printf("Error reading password: %s\n", err)
|
||||||
ret = false
|
ret = false
|
||||||
|
@ -35,6 +35,11 @@ func getAccounts() {
|
|||||||
}
|
}
|
||||||
query.Signup = append(query.Signup, &acctInfo)
|
query.Signup = append(query.Signup, &acctInfo)
|
||||||
|
|
||||||
|
if dryrun {
|
||||||
|
printRequest(client, query)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response, err := client.Request(query)
|
response, err := client.Request(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error requesting account information:", err)
|
fmt.Println("Error requesting account information:", err)
|
||||||
|
@ -20,7 +20,7 @@ var brokerID string
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
defineServerFlags(invDownloadCommand.Flags)
|
defineServerFlags(invDownloadCommand.Flags)
|
||||||
invDownloadCommand.Flags.StringVar(&filename, "filename", "./download.ofx", "The file to save to")
|
invDownloadCommand.Flags.StringVar(&filename, "filename", "./response.ofx", "The file to save to")
|
||||||
invDownloadCommand.Flags.StringVar(&acctID, "acctid", "", "AcctID (from `get-accounts` subcommand)")
|
invDownloadCommand.Flags.StringVar(&acctID, "acctid", "", "AcctID (from `get-accounts` subcommand)")
|
||||||
invDownloadCommand.Flags.StringVar(&brokerID, "brokerid", "", "BrokerID (from `get-accounts` subcommand)")
|
invDownloadCommand.Flags.StringVar(&brokerID, "brokerid", "", "BrokerID (from `get-accounts` subcommand)")
|
||||||
}
|
}
|
||||||
@ -60,6 +60,11 @@ func invDownload() {
|
|||||||
}
|
}
|
||||||
query.InvStmt = append(query.InvStmt, &statementRequest)
|
query.InvStmt = append(query.InvStmt, &statementRequest)
|
||||||
|
|
||||||
|
if dryrun {
|
||||||
|
printRequest(client, query)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response, err := client.RequestNoParse(query)
|
response, err := client.RequestNoParse(query)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -45,6 +45,11 @@ func invTransactions() {
|
|||||||
}
|
}
|
||||||
query.InvStmt = append(query.InvStmt, &statementRequest)
|
query.InvStmt = append(query.InvStmt, &statementRequest)
|
||||||
|
|
||||||
|
if dryrun {
|
||||||
|
printRequest(client, query)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response, err := client.Request(query)
|
response, err := client.Request(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var commands = []command{
|
var commands = []command{
|
||||||
|
profileDownloadCommand,
|
||||||
getAccountsCommand,
|
getAccountsCommand,
|
||||||
downloadCommand,
|
downloadCommand,
|
||||||
ccDownloadCommand,
|
ccDownloadCommand,
|
||||||
|
81
cmd/ofx/profiledownload.go
Normal file
81
cmd/ofx/profiledownload.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"github.com/aclindsa/ofxgo"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var profileDownloadCommand = command{
|
||||||
|
Name: "download-profile",
|
||||||
|
Description: "Download a FI profile to a file",
|
||||||
|
Flags: flag.NewFlagSet("download-profile", flag.ExitOnError),
|
||||||
|
CheckFlags: downloadProfileCheckFlags,
|
||||||
|
Do: downloadProfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
defineServerFlags(profileDownloadCommand.Flags)
|
||||||
|
profileDownloadCommand.Flags.StringVar(&filename, "filename", "./response.ofx", "The file to save to")
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadProfileCheckFlags() bool {
|
||||||
|
// Assume if the user didn't specify username that we should use anonymous
|
||||||
|
// values for it and password
|
||||||
|
if len(username) == 0 {
|
||||||
|
username = "anonymous00000000000000000000000"
|
||||||
|
password = "anonymous00000000000000000000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := checkServerFlags()
|
||||||
|
|
||||||
|
if len(filename) == 0 {
|
||||||
|
fmt.Println("Error: Filename empty")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadProfile() {
|
||||||
|
client, query := newRequest()
|
||||||
|
|
||||||
|
uid, err := ofxgo.RandomUID()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error creating uid for transaction:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
profileRequest := ofxgo.ProfileRequest{
|
||||||
|
TrnUID: *uid,
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Prof = append(query.Prof, &profileRequest)
|
||||||
|
|
||||||
|
if dryrun {
|
||||||
|
printRequest(client, query)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.RequestNoParse(query)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error requesting FI profile:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
file, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error creating file to write to:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(file, response.Body)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error writing response to file:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,8 @@ func newRequest() (ofxgo.Client, *ofxgo.Request) {
|
|||||||
AppVer: appVer,
|
AppVer: appVer,
|
||||||
SpecVersion: ver,
|
SpecVersion: ver,
|
||||||
NoIndent: noIndentRequests,
|
NoIndent: noIndentRequests,
|
||||||
|
CarriageReturn: carriageReturn,
|
||||||
|
UserAgent: userAgent,
|
||||||
})
|
})
|
||||||
|
|
||||||
var query ofxgo.Request
|
var query ofxgo.Request
|
||||||
@ -30,3 +32,14 @@ func newRequest() (ofxgo.Client, *ofxgo.Request) {
|
|||||||
|
|
||||||
return client, &query
|
return client, &query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printRequest(c ofxgo.Client, r *ofxgo.Request) {
|
||||||
|
r.SetClientFields(c)
|
||||||
|
|
||||||
|
b, err := r.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(b)
|
||||||
|
}
|
||||||
|
160
constants.go
160
constants.go
@ -69,11 +69,11 @@ func (e *ofxVersion) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ofxVersion) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e ofxVersion) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(ofxVersions[*e-1], start)
|
enc.EncodeElement(ofxVersions[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,11 +137,11 @@ func (e *acctType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *acctType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e acctType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(acctTypes[*e-1], start)
|
enc.EncodeElement(acctTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,11 +218,11 @@ func (e *trnType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *trnType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e trnType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(trnTypes[*e-1], start)
|
enc.EncodeElement(trnTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,11 +284,11 @@ func (e *imageType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *imageType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e imageType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(imageTypes[*e-1], start)
|
enc.EncodeElement(imageTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,11 +350,11 @@ func (e *imageRefType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) erro
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *imageRefType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e imageRefType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(imageRefTypes[*e-1], start)
|
enc.EncodeElement(imageRefTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,11 +416,11 @@ func (e *checkSup) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *checkSup) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e checkSup) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(checkSups[*e-1], start)
|
enc.EncodeElement(checkSups[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,11 +481,11 @@ func (e *correctAction) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *correctAction) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e correctAction) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(correctActions[*e-1], start)
|
enc.EncodeElement(correctActions[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,11 +547,11 @@ func (e *balType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *balType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e balType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(balTypes[*e-1], start)
|
enc.EncodeElement(balTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,11 +617,11 @@ func (e *inv401kSource) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *inv401kSource) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e inv401kSource) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(inv401kSources[*e-1], start)
|
enc.EncodeElement(inv401kSources[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,11 +684,11 @@ func (e *subAcctType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *subAcctType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e subAcctType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(subAcctTypes[*e-1], start)
|
enc.EncodeElement(subAcctTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -749,11 +749,11 @@ func (e *buyType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *buyType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e buyType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(buyTypes[*e-1], start)
|
enc.EncodeElement(buyTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,11 +815,11 @@ func (e *optAction) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *optAction) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e optAction) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(optActions[*e-1], start)
|
enc.EncodeElement(optActions[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -880,11 +880,11 @@ func (e *tferAction) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *tferAction) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e tferAction) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(tferActions[*e-1], start)
|
enc.EncodeElement(tferActions[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,11 +945,11 @@ func (e *posType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *posType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e posType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(posTypes[*e-1], start)
|
enc.EncodeElement(posTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,11 +1010,11 @@ func (e *secured) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *secured) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e secured) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(secureds[*e-1], start)
|
enc.EncodeElement(secureds[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1076,11 +1076,11 @@ func (e *duration) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *duration) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e duration) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(durations[*e-1], start)
|
enc.EncodeElement(durations[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1142,11 +1142,11 @@ func (e *restriction) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *restriction) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e restriction) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(restrictions[*e-1], start)
|
enc.EncodeElement(restrictions[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1207,11 +1207,11 @@ func (e *unitType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *unitType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e unitType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(unitTypes[*e-1], start)
|
enc.EncodeElement(unitTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1272,11 +1272,11 @@ func (e *optBuyType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *optBuyType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e optBuyType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(optBuyTypes[*e-1], start)
|
enc.EncodeElement(optBuyTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1337,11 +1337,11 @@ func (e *sellType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *sellType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e sellType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(sellTypes[*e-1], start)
|
enc.EncodeElement(sellTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1410,11 +1410,11 @@ func (e *loanPmtFreq) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *loanPmtFreq) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e loanPmtFreq) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(loanPmtFreqs[*e-1], start)
|
enc.EncodeElement(loanPmtFreqs[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1478,11 +1478,11 @@ func (e *incomeType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *incomeType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e incomeType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(incomeTypes[*e-1], start)
|
enc.EncodeElement(incomeTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1544,11 +1544,11 @@ func (e *sellReason) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *sellReason) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e sellReason) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(sellReasons[*e-1], start)
|
enc.EncodeElement(sellReasons[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1609,11 +1609,11 @@ func (e *optSellType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *optSellType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e optSellType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(optSellTypes[*e-1], start)
|
enc.EncodeElement(optSellTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1676,11 +1676,11 @@ func (e *relType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *relType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e relType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(relTypes[*e-1], start)
|
enc.EncodeElement(relTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1743,11 +1743,11 @@ func (e *charType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *charType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e charType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(charTypes[*e-1], start)
|
enc.EncodeElement(charTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1808,11 +1808,11 @@ func (e *syncMode) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *syncMode) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e syncMode) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(syncModes[*e-1], start)
|
enc.EncodeElement(syncModes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1873,11 +1873,11 @@ func (e *ofxSec) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ofxSec) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e ofxSec) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(ofxSecs[*e-1], start)
|
enc.EncodeElement(ofxSecs[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1938,11 +1938,11 @@ func (e *debtType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *debtType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e debtType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(debtTypes[*e-1], start)
|
enc.EncodeElement(debtTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2005,11 +2005,11 @@ func (e *debtClass) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *debtClass) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e debtClass) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(debtClasss[*e-1], start)
|
enc.EncodeElement(debtClasss[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2073,11 +2073,11 @@ func (e *couponFreq) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *couponFreq) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e couponFreq) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(couponFreqs[*e-1], start)
|
enc.EncodeElement(couponFreqs[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2140,11 +2140,11 @@ func (e *callType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *callType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e callType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(callTypes[*e-1], start)
|
enc.EncodeElement(callTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2210,11 +2210,11 @@ func (e *assetClass) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *assetClass) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e assetClass) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(assetClasss[*e-1], start)
|
enc.EncodeElement(assetClasss[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2276,11 +2276,11 @@ func (e *mfType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *mfType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e mfType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(mfTypes[*e-1], start)
|
enc.EncodeElement(mfTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2341,11 +2341,11 @@ func (e *optType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *optType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e optType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(optTypes[*e-1], start)
|
enc.EncodeElement(optTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2408,11 +2408,11 @@ func (e *stockType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *stockType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e stockType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(stockTypes[*e-1], start)
|
enc.EncodeElement(stockTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2476,11 +2476,11 @@ func (e *holderType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *holderType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e holderType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(holderTypes[*e-1], start)
|
enc.EncodeElement(holderTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2543,11 +2543,11 @@ func (e *acctClassification) UnmarshalXML(d *xml.Decoder, start xml.StartElement
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *acctClassification) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e acctClassification) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(acctClassifications[*e-1], start)
|
enc.EncodeElement(acctClassifications[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2609,11 +2609,11 @@ func (e *svcStatus) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *svcStatus) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e svcStatus) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(svcStatuss[*e-1], start)
|
enc.EncodeElement(svcStatuss[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2683,11 +2683,11 @@ func (e *usProductType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *usProductType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
func (e usProductType) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
if !e.Valid() {
|
if !e.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
enc.EncodeElement(usProductTypes[*e-1], start)
|
enc.EncodeElement(usProductTypes[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,18 @@ func TestOfxVersion(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E ofxVersion
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct OfxVersion): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>220</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>220</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAcctType(t *testing.T) {
|
func TestAcctType(t *testing.T) {
|
||||||
@ -101,6 +113,18 @@ func TestAcctType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E acctType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct AcctType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>CD</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>CD</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTrnType(t *testing.T) {
|
func TestTrnType(t *testing.T) {
|
||||||
@ -146,6 +170,18 @@ func TestTrnType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E trnType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct TrnType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImageType(t *testing.T) {
|
func TestImageType(t *testing.T) {
|
||||||
@ -191,6 +227,18 @@ func TestImageType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E imageType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct ImageType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>TAX</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>TAX</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImageRefType(t *testing.T) {
|
func TestImageRefType(t *testing.T) {
|
||||||
@ -236,6 +284,18 @@ func TestImageRefType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E imageRefType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct ImageRefType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>FORMURL</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>FORMURL</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSup(t *testing.T) {
|
func TestCheckSup(t *testing.T) {
|
||||||
@ -281,6 +341,18 @@ func TestCheckSup(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E checkSup
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct CheckSup): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>FRONTANDBACK</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>FRONTANDBACK</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCorrectAction(t *testing.T) {
|
func TestCorrectAction(t *testing.T) {
|
||||||
@ -326,6 +398,18 @@ func TestCorrectAction(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E correctAction
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct CorrectAction): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>REPLACE</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>REPLACE</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBalType(t *testing.T) {
|
func TestBalType(t *testing.T) {
|
||||||
@ -371,6 +455,18 @@ func TestBalType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E balType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct BalType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>NUMBER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>NUMBER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInv401kSource(t *testing.T) {
|
func TestInv401kSource(t *testing.T) {
|
||||||
@ -416,6 +512,18 @@ func TestInv401kSource(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E inv401kSource
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct Inv401kSource): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHERNONVEST</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHERNONVEST</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSubAcctType(t *testing.T) {
|
func TestSubAcctType(t *testing.T) {
|
||||||
@ -461,6 +569,18 @@ func TestSubAcctType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E subAcctType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct SubAcctType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuyType(t *testing.T) {
|
func TestBuyType(t *testing.T) {
|
||||||
@ -506,6 +626,18 @@ func TestBuyType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E buyType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct BuyType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>BUYTOCOVER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>BUYTOCOVER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptAction(t *testing.T) {
|
func TestOptAction(t *testing.T) {
|
||||||
@ -551,6 +683,18 @@ func TestOptAction(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E optAction
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct OptAction): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>EXPIRE</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>EXPIRE</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTferAction(t *testing.T) {
|
func TestTferAction(t *testing.T) {
|
||||||
@ -596,6 +740,18 @@ func TestTferAction(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E tferAction
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct TferAction): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OUT</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OUT</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPosType(t *testing.T) {
|
func TestPosType(t *testing.T) {
|
||||||
@ -641,6 +797,18 @@ func TestPosType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E posType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct PosType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>SHORT</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>SHORT</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSecured(t *testing.T) {
|
func TestSecured(t *testing.T) {
|
||||||
@ -686,6 +854,18 @@ func TestSecured(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E secured
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct Secured): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>COVERED</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>COVERED</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDuration(t *testing.T) {
|
func TestDuration(t *testing.T) {
|
||||||
@ -731,6 +911,18 @@ func TestDuration(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E duration
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct Duration): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>IMMEDIATE</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>IMMEDIATE</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRestriction(t *testing.T) {
|
func TestRestriction(t *testing.T) {
|
||||||
@ -776,6 +968,18 @@ func TestRestriction(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E restriction
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct Restriction): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>NONE</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>NONE</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnitType(t *testing.T) {
|
func TestUnitType(t *testing.T) {
|
||||||
@ -821,6 +1025,18 @@ func TestUnitType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E unitType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct UnitType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>CURRENCY</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>CURRENCY</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptBuyType(t *testing.T) {
|
func TestOptBuyType(t *testing.T) {
|
||||||
@ -866,6 +1082,18 @@ func TestOptBuyType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E optBuyType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct OptBuyType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>BUYTOCLOSE</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>BUYTOCLOSE</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSellType(t *testing.T) {
|
func TestSellType(t *testing.T) {
|
||||||
@ -911,6 +1139,18 @@ func TestSellType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E sellType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct SellType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>SELLSHORT</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>SELLSHORT</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoanPmtFreq(t *testing.T) {
|
func TestLoanPmtFreq(t *testing.T) {
|
||||||
@ -956,6 +1196,18 @@ func TestLoanPmtFreq(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E loanPmtFreq
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct LoanPmtFreq): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIncomeType(t *testing.T) {
|
func TestIncomeType(t *testing.T) {
|
||||||
@ -1001,6 +1253,18 @@ func TestIncomeType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E incomeType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct IncomeType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>MISC</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>MISC</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSellReason(t *testing.T) {
|
func TestSellReason(t *testing.T) {
|
||||||
@ -1046,6 +1310,18 @@ func TestSellReason(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E sellReason
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct SellReason): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>MATURITY</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>MATURITY</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptSellType(t *testing.T) {
|
func TestOptSellType(t *testing.T) {
|
||||||
@ -1091,6 +1367,18 @@ func TestOptSellType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E optSellType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct OptSellType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>SELLTOOPEN</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>SELLTOOPEN</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRelType(t *testing.T) {
|
func TestRelType(t *testing.T) {
|
||||||
@ -1136,6 +1424,18 @@ func TestRelType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E relType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct RelType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCharType(t *testing.T) {
|
func TestCharType(t *testing.T) {
|
||||||
@ -1181,6 +1481,18 @@ func TestCharType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E charType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct CharType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>ALPHAANDNUMERIC</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>ALPHAANDNUMERIC</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncMode(t *testing.T) {
|
func TestSyncMode(t *testing.T) {
|
||||||
@ -1226,6 +1538,18 @@ func TestSyncMode(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E syncMode
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct SyncMode): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>LITE</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>LITE</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOfxSec(t *testing.T) {
|
func TestOfxSec(t *testing.T) {
|
||||||
@ -1271,6 +1595,18 @@ func TestOfxSec(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E ofxSec
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct OfxSec): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>TYPE 1</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>TYPE 1</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDebtType(t *testing.T) {
|
func TestDebtType(t *testing.T) {
|
||||||
@ -1316,6 +1652,18 @@ func TestDebtType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E debtType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct DebtType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>ZERO</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>ZERO</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDebtClass(t *testing.T) {
|
func TestDebtClass(t *testing.T) {
|
||||||
@ -1361,6 +1709,18 @@ func TestDebtClass(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E debtClass
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct DebtClass): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCouponFreq(t *testing.T) {
|
func TestCouponFreq(t *testing.T) {
|
||||||
@ -1406,6 +1766,18 @@ func TestCouponFreq(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E couponFreq
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct CouponFreq): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCallType(t *testing.T) {
|
func TestCallType(t *testing.T) {
|
||||||
@ -1451,6 +1823,18 @@ func TestCallType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E callType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct CallType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>MATURITY</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>MATURITY</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAssetClass(t *testing.T) {
|
func TestAssetClass(t *testing.T) {
|
||||||
@ -1496,6 +1880,18 @@ func TestAssetClass(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E assetClass
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct AssetClass): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMfType(t *testing.T) {
|
func TestMfType(t *testing.T) {
|
||||||
@ -1541,6 +1937,18 @@ func TestMfType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E mfType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct MfType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptType(t *testing.T) {
|
func TestOptType(t *testing.T) {
|
||||||
@ -1586,6 +1994,18 @@ func TestOptType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E optType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct OptType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>CALL</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>CALL</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStockType(t *testing.T) {
|
func TestStockType(t *testing.T) {
|
||||||
@ -1631,6 +2051,18 @@ func TestStockType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E stockType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct StockType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHolderType(t *testing.T) {
|
func TestHolderType(t *testing.T) {
|
||||||
@ -1676,6 +2108,18 @@ func TestHolderType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E holderType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct HolderType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAcctClassification(t *testing.T) {
|
func TestAcctClassification(t *testing.T) {
|
||||||
@ -1721,6 +2165,18 @@ func TestAcctClassification(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E acctClassification
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct AcctClassification): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>OTHER</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>OTHER</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSvcStatus(t *testing.T) {
|
func TestSvcStatus(t *testing.T) {
|
||||||
@ -1766,6 +2222,18 @@ func TestSvcStatus(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E svcStatus
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct SvcStatus): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>ACTIVE</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>ACTIVE</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUsProductType(t *testing.T) {
|
func TestUsProductType(t *testing.T) {
|
||||||
@ -1811,4 +2279,16 @@ func TestUsProductType(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\n")
|
t.Fatalf("Expected error unmarshalling garbage value\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SC struct {
|
||||||
|
E usProductType
|
||||||
|
}
|
||||||
|
sc := SC{E: e}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct UsProductType): %s\n", err)
|
||||||
|
}
|
||||||
|
if string(b) != "<SC><E>UGMA</E></SC>" {
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\n", "<SC><E>UGMA</E></SC>", string(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ type DiscoverCardClient struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewDiscoverCardClient returns a Client interface configured to handle
|
// NewDiscoverCardClient returns a Client interface configured to handle
|
||||||
// Discover Card's brand of idiosyncracy
|
// Discover Card's brand of idiosyncrasy
|
||||||
func NewDiscoverCardClient(bc *BasicClient) Client {
|
func NewDiscoverCardClient(bc *BasicClient) Client {
|
||||||
return &DiscoverCardClient{bc}
|
return &DiscoverCardClient{bc}
|
||||||
}
|
}
|
||||||
@ -77,6 +77,8 @@ func discoverCardHTTPPost(URL string, r io.Reader) (*http.Response, error) {
|
|||||||
return http.ReadResponse(bufio.NewReader(conn), nil)
|
return http.ReadResponse(bufio.NewReader(conn), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RawRequest is a convenience wrapper around http.Post. It is exposed only for
|
||||||
|
// when you need to read/inspect the raw HTTP response yourself.
|
||||||
func (c *DiscoverCardClient) RawRequest(URL string, r io.Reader) (*http.Response, error) {
|
func (c *DiscoverCardClient) RawRequest(URL string, r io.Reader) (*http.Response, error) {
|
||||||
if !strings.HasPrefix(URL, "https://") {
|
if !strings.HasPrefix(URL, "https://") {
|
||||||
return nil, errors.New("Refusing to send OFX request with possible plain-text password over non-https protocol")
|
return nil, errors.New("Refusing to send OFX request with possible plain-text password over non-https protocol")
|
||||||
@ -94,10 +96,14 @@ func (c *DiscoverCardClient) RawRequest(URL string, r io.Reader) (*http.Response
|
|||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestNoParse marshals a Request to XML, makes an HTTP request, and returns
|
||||||
|
// the raw HTTP response
|
||||||
func (c *DiscoverCardClient) RequestNoParse(r *Request) (*http.Response, error) {
|
func (c *DiscoverCardClient) RequestNoParse(r *Request) (*http.Response, error) {
|
||||||
return clientRequestNoParse(c, r)
|
return clientRequestNoParse(c, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request marshals a Request to XML, makes an HTTP request, and then
|
||||||
|
// unmarshals the response into a Response object.
|
||||||
func (c *DiscoverCardClient) Request(r *Request) (*Response, error) {
|
func (c *DiscoverCardClient) Request(r *Request) (*Response, error) {
|
||||||
return clientRequest(c, r)
|
return clientRequest(c, r)
|
||||||
}
|
}
|
||||||
|
@ -116,11 +116,11 @@ func (e *{enumLower}) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
return e.FromString(value)
|
return e.FromString(value)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
func (e *{enumLower}) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {{
|
func (e {enumLower}) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {{
|
||||||
if !e.Valid() {{
|
if !e.Valid() {{
|
||||||
return nil
|
return nil
|
||||||
}}
|
}}
|
||||||
enc.EncodeElement({enumLower}s[*e-1], start)
|
enc.EncodeElement({enumLower}s[e-1], start)
|
||||||
return nil
|
return nil
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -225,6 +225,18 @@ func Test{enum}(t *testing.T) {{
|
|||||||
if err == nil {{
|
if err == nil {{
|
||||||
t.Fatalf("Expected error unmarshalling garbage value\\n")
|
t.Fatalf("Expected error unmarshalling garbage value\\n")
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
type SC struct {{
|
||||||
|
E {enumLower}
|
||||||
|
}}
|
||||||
|
sc := SC{{E: e}}
|
||||||
|
b, err = xml.Marshal(sc)
|
||||||
|
if err != nil {{
|
||||||
|
t.Fatalf("Unexpected error on xml.Marshal(struct {enum}): %s\\n", err)
|
||||||
|
}}
|
||||||
|
if string(b) != "<SC><E>{lastValueUpper}</E></SC>" {{
|
||||||
|
t.Fatalf("Expected '%s', got '%s'\\n", "<SC><E>{lastValueUpper}</E></SC>", string(b))
|
||||||
|
}}
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -232,8 +244,10 @@ with open("constants_test.go", 'w') as f:
|
|||||||
f.write(test_header)
|
f.write(test_header)
|
||||||
|
|
||||||
for enum in enums:
|
for enum in enums:
|
||||||
|
enumLower = enum[:1].lower() + enum[1:].replace(" ", "")
|
||||||
firstValueUpper = enums[enum][0][0].upper()
|
firstValueUpper = enums[enum][0][0].upper()
|
||||||
lastValueUpper = enums[enum][0][-1].upper()
|
lastValueUpper = enums[enum][0][-1].upper()
|
||||||
f.write(test_template.format(enum=enum,
|
f.write(test_template.format(enum=enum,
|
||||||
|
enumLower=enumLower,
|
||||||
firstValueUpper=firstValueUpper,
|
firstValueUpper=firstValueUpper,
|
||||||
lastValueUpper=lastValueUpper))
|
lastValueUpper=lastValueUpper))
|
||||||
|
8
go.mod
8
go.mod
@ -1,11 +1,9 @@
|
|||||||
module github.com/aclindsa/ofxgo
|
module github.com/aclindsa/ofxgo
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aclindsa/xml v0.0.0-20190701095008-453d2c6090c2
|
github.com/aclindsa/xml v0.0.0-20201125035057-bbd5c9ec99ac
|
||||||
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4 // indirect
|
golang.org/x/text v0.3.7
|
||||||
golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 // indirect
|
|
||||||
golang.org/x/text v0.0.0-20180911161511-905a57155faa
|
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.9
|
go 1.9
|
||||||
|
23
go.sum
23
go.sum
@ -1,14 +1,9 @@
|
|||||||
github.com/aclindsa/xml v0.0.0-20171002130543-5d4402bb4a20 h1:wN3KlzWq56AIgOqFzYLYVih4zVyPDViCUeG5uZxJHq4=
|
github.com/aclindsa/xml v0.0.0-20201125035057-bbd5c9ec99ac h1:xCNSfPWpcx3Sdz/+aB/Re4L8oA6Y4kRRRuTh1CHCDEw=
|
||||||
github.com/aclindsa/xml v0.0.0-20171002130543-5d4402bb4a20/go.mod h1:DiEHtTD+e6zS3+R95F05Bfbcsfv13wZTi2M4LfAFLBE=
|
github.com/aclindsa/xml v0.0.0-20201125035057-bbd5c9ec99ac/go.mod h1:GjqOUT8xlg5+T19lFv6yAGNrtMKkZ839Gt4e16mBXlY=
|
||||||
github.com/aclindsa/xml v0.0.0-20190625094425-0aa7a3409cf4 h1:STo5wlCItpgL9LFBui17kZ/N1iKQk+UztLRj2cVkSXQ=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||||
github.com/aclindsa/xml v0.0.0-20190625094425-0aa7a3409cf4/go.mod h1:GjqOUT8xlg5+T19lFv6yAGNrtMKkZ839Gt4e16mBXlY=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
github.com/aclindsa/xml v0.0.0-20190701095008-453d2c6090c2 h1:ICeGSGrc6fd81VtQ3nZ2h7GEOKxWYwRxjW0v0d/mgu4=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
github.com/aclindsa/xml v0.0.0-20190701095008-453d2c6090c2/go.mod h1:GjqOUT8xlg5+T19lFv6yAGNrtMKkZ839Gt4e16mBXlY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c h1:kQWxfPIHVLbgLzphqk3QUflDy9QdksZR4ygR807bpy0=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4 h1:Vk3wNqEZwyGyei9yq5ekj7frek2u7HUfffJ1/opblzc=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 h1:O33LKL7WyJgjN9CvxfTIomjIClbd/Kq86/iipowHQU0=
|
|
||||||
golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/text v0.0.0-20180911161511-905a57155faa h1:uIJ7KxPgS7ODNO//HqlPfjWmWDGRsoONAVcEVaJNWNs=
|
|
||||||
golang.org/x/text v0.0.0-20180911161511-905a57155faa/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
|
121
invstmt.go
121
invstmt.go
@ -103,7 +103,7 @@ type InvSell struct {
|
|||||||
Taxes Amount `xml:"TAXES,omitempty"`
|
Taxes Amount `xml:"TAXES,omitempty"`
|
||||||
Fees Amount `xml:"FEES,omitempty"`
|
Fees Amount `xml:"FEES,omitempty"`
|
||||||
Load Amount `xml:"LOAD,omitempty"`
|
Load Amount `xml:"LOAD,omitempty"`
|
||||||
Witholding Amount `xml:"WITHHOLDING,omitempty"` // Federal tax witholdings
|
Withholding Amount `xml:"WITHHOLDING,omitempty"` // Federal tax withholdings
|
||||||
TaxExempt Boolean `xml:"TAXEXEMPT,omitempty"` // Tax-exempt transaction
|
TaxExempt Boolean `xml:"TAXEXEMPT,omitempty"` // Tax-exempt transaction
|
||||||
Total Amount `xml:"TOTAL"` // Transaction total. Buys, sells, etc.:((quan. * (price +/- markup/markdown)) +/-(commission + fees + load + taxes + penalty + withholding + statewithholding)). Distributions, interest, margin interest, misc. expense, etc.: amount. Return of cap: cost basis
|
Total Amount `xml:"TOTAL"` // Transaction total. Buys, sells, etc.:((quan. * (price +/- markup/markdown)) +/-(commission + fees + load + taxes + penalty + withholding + statewithholding)). Distributions, interest, margin interest, misc. expense, etc.: amount. Return of cap: cost basis
|
||||||
Gain Amount `xml:"GAIN,omitempty"` // Total gain
|
Gain Amount `xml:"GAIN,omitempty"` // Total gain
|
||||||
@ -113,7 +113,7 @@ type InvSell struct {
|
|||||||
SubAcctFund subAcctType `xml:"SUBACCTFUND"` // Where did the money for the transaction come from or go to? CASH, MARGIN, SHORT, OTHER
|
SubAcctFund subAcctType `xml:"SUBACCTFUND"` // Where did the money for the transaction come from or go to? CASH, MARGIN, SHORT, OTHER
|
||||||
|
|
||||||
LoanID String `xml:"LOANID,omitempty"` // For 401(k) accounts only. Indicates that the transaction was due to a loan or a loan repayment, and which loan it was
|
LoanID String `xml:"LOANID,omitempty"` // For 401(k) accounts only. Indicates that the transaction was due to a loan or a loan repayment, and which loan it was
|
||||||
StateWitholding Amount `xml:"STATEWITHHOLDING,omitempty"` // State tax witholdings
|
StateWithholding Amount `xml:"STATEWITHHOLDING,omitempty"` // State tax withholdings
|
||||||
Penalty Amount `xml:"PENALTY,omitempty"` // Amount withheld due to penalty
|
Penalty Amount `xml:"PENALTY,omitempty"` // Amount withheld due to penalty
|
||||||
|
|
||||||
Inv401kSource inv401kSource `xml:"INV401KSOURCE,omitempty"` // Source of money for this transaction. One of PRETAX, AFTERTAX, MATCH, PROFITSHARING, ROLLOVER, OTHERVEST, OTHERNONVEST for 401(k) accounts. Default if not present is OTHERNONVEST. The following cash source types are subject to vesting: MATCH, PROFITSHARING, and OTHERVEST
|
Inv401kSource inv401kSource `xml:"INV401KSOURCE,omitempty"` // Source of money for this transaction. One of PRETAX, AFTERTAX, MATCH, PROFITSHARING, ROLLOVER, OTHERVEST, OTHERNONVEST for 401(k) accounts. Default if not present is OTHERNONVEST. The following cash source types are subject to vesting: MATCH, PROFITSHARING, and OTHERVEST
|
||||||
@ -131,6 +131,10 @@ func (t BuyDebt) TransactionType() string {
|
|||||||
return "BUYDEBT"
|
return "BUYDEBT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t BuyDebt) InvTransaction() InvTran {
|
||||||
|
return t.InvBuy.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// BuyMF represents a transaction purchasing a mutual fund
|
// BuyMF represents a transaction purchasing a mutual fund
|
||||||
type BuyMF struct {
|
type BuyMF struct {
|
||||||
XMLName xml.Name `xml:"BUYMF"`
|
XMLName xml.Name `xml:"BUYMF"`
|
||||||
@ -144,6 +148,10 @@ func (t BuyMF) TransactionType() string {
|
|||||||
return "BUYMF"
|
return "BUYMF"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t BuyMF) InvTransaction() InvTran {
|
||||||
|
return t.InvBuy.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// BuyOpt represents a transaction purchasing an option
|
// BuyOpt represents a transaction purchasing an option
|
||||||
type BuyOpt struct {
|
type BuyOpt struct {
|
||||||
XMLName xml.Name `xml:"BUYOPT"`
|
XMLName xml.Name `xml:"BUYOPT"`
|
||||||
@ -157,6 +165,10 @@ func (t BuyOpt) TransactionType() string {
|
|||||||
return "BUYOPT"
|
return "BUYOPT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t BuyOpt) InvTransaction() InvTran {
|
||||||
|
return t.InvBuy.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// BuyOther represents a transaction purchasing a type of security not covered
|
// BuyOther represents a transaction purchasing a type of security not covered
|
||||||
// by the other Buy* structs
|
// by the other Buy* structs
|
||||||
type BuyOther struct {
|
type BuyOther struct {
|
||||||
@ -169,6 +181,10 @@ func (t BuyOther) TransactionType() string {
|
|||||||
return "BUYOTHER"
|
return "BUYOTHER"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t BuyOther) InvTransaction() InvTran {
|
||||||
|
return t.InvBuy.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// BuyStock represents a transaction purchasing stock
|
// BuyStock represents a transaction purchasing stock
|
||||||
type BuyStock struct {
|
type BuyStock struct {
|
||||||
XMLName xml.Name `xml:"BUYSTOCK"`
|
XMLName xml.Name `xml:"BUYSTOCK"`
|
||||||
@ -181,6 +197,10 @@ func (t BuyStock) TransactionType() string {
|
|||||||
return "BUYSTOCK"
|
return "BUYSTOCK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t BuyStock) InvTransaction() InvTran {
|
||||||
|
return t.InvBuy.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// ClosureOpt represents a transaction closing a position for an option
|
// ClosureOpt represents a transaction closing a position for an option
|
||||||
type ClosureOpt struct {
|
type ClosureOpt struct {
|
||||||
XMLName xml.Name `xml:"CLOSUREOPT"`
|
XMLName xml.Name `xml:"CLOSUREOPT"`
|
||||||
@ -199,6 +219,10 @@ func (t ClosureOpt) TransactionType() string {
|
|||||||
return "CLOSUREOPT"
|
return "CLOSUREOPT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t ClosureOpt) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// Income represents a transaction where investment income is being realized as
|
// Income represents a transaction where investment income is being realized as
|
||||||
// cash into the investment account
|
// cash into the investment account
|
||||||
type Income struct {
|
type Income struct {
|
||||||
@ -210,7 +234,7 @@ type Income struct {
|
|||||||
SubAcctSec subAcctType `xml:"SUBACCTSEC"` // Sub-account type for this security. One of CASH, MARGIN, SHORT, OTHER
|
SubAcctSec subAcctType `xml:"SUBACCTSEC"` // Sub-account type for this security. One of CASH, MARGIN, SHORT, OTHER
|
||||||
SubAcctFund subAcctType `xml:"SUBACCTFUND"` // Where did the money for the transaction come from or go to? CASH, MARGIN, SHORT, OTHER
|
SubAcctFund subAcctType `xml:"SUBACCTFUND"` // Where did the money for the transaction come from or go to? CASH, MARGIN, SHORT, OTHER
|
||||||
TaxExempt Boolean `xml:"TAXEXEMPT,omitempty"` // Tax-exempt transaction
|
TaxExempt Boolean `xml:"TAXEXEMPT,omitempty"` // Tax-exempt transaction
|
||||||
Witholding Amount `xml:"WITHHOLDING,omitempty"` // Federal tax witholdings
|
Withholding Amount `xml:"WITHHOLDING,omitempty"` // Federal tax withholdings
|
||||||
Currency Currency `xml:"CURRENCY,omitempty"` // Represents the currency this transaction is in (instead of CURDEF in INVSTMTRS) if Valid()
|
Currency Currency `xml:"CURRENCY,omitempty"` // Represents the currency this transaction is in (instead of CURDEF in INVSTMTRS) if Valid()
|
||||||
OrigCurrency Currency `xml:"ORIGCURRENCY,omitempty"` // Represents the currency this transaction was converted to INVSTMTRS' CURDEF from if Valid
|
OrigCurrency Currency `xml:"ORIGCURRENCY,omitempty"` // Represents the currency this transaction was converted to INVSTMTRS' CURDEF from if Valid
|
||||||
Inv401kSource inv401kSource `xml:"INV401KSOURCE,omitempty"` // Source of money for this transaction. One of PRETAX, AFTERTAX, MATCH, PROFITSHARING, ROLLOVER, OTHERVEST, OTHERNONVEST for 401(k) accounts. Default if not present is OTHERNONVEST. The following cash source types are subject to vesting: MATCH, PROFITSHARING, and OTHERVEST
|
Inv401kSource inv401kSource `xml:"INV401KSOURCE,omitempty"` // Source of money for this transaction. One of PRETAX, AFTERTAX, MATCH, PROFITSHARING, ROLLOVER, OTHERVEST, OTHERNONVEST for 401(k) accounts. Default if not present is OTHERNONVEST. The following cash source types are subject to vesting: MATCH, PROFITSHARING, and OTHERVEST
|
||||||
@ -221,6 +245,10 @@ func (t Income) TransactionType() string {
|
|||||||
return "INCOME"
|
return "INCOME"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Income) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// InvExpense represents a transaction realizing an expense associated with an
|
// InvExpense represents a transaction realizing an expense associated with an
|
||||||
// investment
|
// investment
|
||||||
type InvExpense struct {
|
type InvExpense struct {
|
||||||
@ -240,6 +268,10 @@ func (t InvExpense) TransactionType() string {
|
|||||||
return "INVEXPENSE"
|
return "INVEXPENSE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t InvExpense) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// JrnlFund represents a transaction journaling cash holdings between
|
// JrnlFund represents a transaction journaling cash holdings between
|
||||||
// sub-accounts within the same investment account
|
// sub-accounts within the same investment account
|
||||||
type JrnlFund struct {
|
type JrnlFund struct {
|
||||||
@ -255,6 +287,10 @@ func (t JrnlFund) TransactionType() string {
|
|||||||
return "JRNLFUND"
|
return "JRNLFUND"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t JrnlFund) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// JrnlSec represents a transaction journaling security holdings between
|
// JrnlSec represents a transaction journaling security holdings between
|
||||||
// sub-accounts within the same investment account
|
// sub-accounts within the same investment account
|
||||||
type JrnlSec struct {
|
type JrnlSec struct {
|
||||||
@ -271,6 +307,10 @@ func (t JrnlSec) TransactionType() string {
|
|||||||
return "JRNLSEC"
|
return "JRNLSEC"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t JrnlSec) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// MarginInterest represents a transaction realizing a margin interest expense
|
// MarginInterest represents a transaction realizing a margin interest expense
|
||||||
type MarginInterest struct {
|
type MarginInterest struct {
|
||||||
XMLName xml.Name `xml:"MARGININTEREST"`
|
XMLName xml.Name `xml:"MARGININTEREST"`
|
||||||
@ -286,6 +326,10 @@ func (t MarginInterest) TransactionType() string {
|
|||||||
return "MARGININTEREST"
|
return "MARGININTEREST"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t MarginInterest) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// Reinvest is a single transaction that contains both income and an investment
|
// Reinvest is a single transaction that contains both income and an investment
|
||||||
// transaction. If servers can’t track this as a single transaction they should
|
// transaction. If servers can’t track this as a single transaction they should
|
||||||
// return an Income transaction and an InvTran.
|
// return an Income transaction and an InvTran.
|
||||||
@ -313,6 +357,10 @@ func (t Reinvest) TransactionType() string {
|
|||||||
return "REINVEST"
|
return "REINVEST"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Reinvest) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// RetOfCap represents a transaction where capital is being returned to the
|
// RetOfCap represents a transaction where capital is being returned to the
|
||||||
// account holder
|
// account holder
|
||||||
type RetOfCap struct {
|
type RetOfCap struct {
|
||||||
@ -332,6 +380,10 @@ func (t RetOfCap) TransactionType() string {
|
|||||||
return "RETOFCAP"
|
return "RETOFCAP"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t RetOfCap) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// SellDebt represents the sale of a debt security. Used when debt is sold,
|
// SellDebt represents the sale of a debt security. Used when debt is sold,
|
||||||
// called, or reaches maturity.
|
// called, or reaches maturity.
|
||||||
type SellDebt struct {
|
type SellDebt struct {
|
||||||
@ -346,6 +398,10 @@ func (t SellDebt) TransactionType() string {
|
|||||||
return "SELLDEBT"
|
return "SELLDEBT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t SellDebt) InvTransaction() InvTran {
|
||||||
|
return t.InvSell.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// SellMF represents a transaction selling a mutual fund
|
// SellMF represents a transaction selling a mutual fund
|
||||||
type SellMF struct {
|
type SellMF struct {
|
||||||
XMLName xml.Name `xml:"SELLMF"`
|
XMLName xml.Name `xml:"SELLMF"`
|
||||||
@ -360,6 +416,10 @@ func (t SellMF) TransactionType() string {
|
|||||||
return "SELLMF"
|
return "SELLMF"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t SellMF) InvTransaction() InvTran {
|
||||||
|
return t.InvSell.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// SellOpt represents a transaction selling an option. Depending on the value
|
// SellOpt represents a transaction selling an option. Depending on the value
|
||||||
// of OptSellType, can be used to sell a previously bought option or write a
|
// of OptSellType, can be used to sell a previously bought option or write a
|
||||||
// new option.
|
// new option.
|
||||||
@ -378,6 +438,10 @@ func (t SellOpt) TransactionType() string {
|
|||||||
return "SELLOPT"
|
return "SELLOPT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t SellOpt) InvTransaction() InvTran {
|
||||||
|
return t.InvSell.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// SellOther represents a transaction selling a security type not covered by
|
// SellOther represents a transaction selling a security type not covered by
|
||||||
// the other Sell* structs
|
// the other Sell* structs
|
||||||
type SellOther struct {
|
type SellOther struct {
|
||||||
@ -390,6 +454,10 @@ func (t SellOther) TransactionType() string {
|
|||||||
return "SELLOTHER"
|
return "SELLOTHER"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t SellOther) InvTransaction() InvTran {
|
||||||
|
return t.InvSell.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// SellStock represents a transaction selling stock
|
// SellStock represents a transaction selling stock
|
||||||
type SellStock struct {
|
type SellStock struct {
|
||||||
XMLName xml.Name `xml:"SELLSTOCK"`
|
XMLName xml.Name `xml:"SELLSTOCK"`
|
||||||
@ -402,6 +470,10 @@ func (t SellStock) TransactionType() string {
|
|||||||
return "SELLSTOCK"
|
return "SELLSTOCK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t SellStock) InvTransaction() InvTran {
|
||||||
|
return t.InvSell.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// Split represents a stock or mutual fund split
|
// Split represents a stock or mutual fund split
|
||||||
type Split struct {
|
type Split struct {
|
||||||
XMLName xml.Name `xml:"SPLIT"`
|
XMLName xml.Name `xml:"SPLIT"`
|
||||||
@ -424,6 +496,10 @@ func (t Split) TransactionType() string {
|
|||||||
return "SPLIT"
|
return "SPLIT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Split) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// Transfer represents the transfer of securities into or out of an account
|
// Transfer represents the transfer of securities into or out of an account
|
||||||
type Transfer struct {
|
type Transfer struct {
|
||||||
XMLName xml.Name `xml:"TRANSFER"`
|
XMLName xml.Name `xml:"TRANSFER"`
|
||||||
@ -445,10 +521,15 @@ func (t Transfer) TransactionType() string {
|
|||||||
return "TRANSFER"
|
return "TRANSFER"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Transfer) InvTransaction() InvTran {
|
||||||
|
return t.InvTran
|
||||||
|
}
|
||||||
|
|
||||||
// InvTransaction is a generic interface met by all investment transactions
|
// InvTransaction is a generic interface met by all investment transactions
|
||||||
// (Buy*, Sell*, & co.)
|
// (Buy*, Sell*, & co.)
|
||||||
type InvTransaction interface {
|
type InvTransaction interface {
|
||||||
TransactionType() string
|
TransactionType() string
|
||||||
|
InvTransaction() InvTran
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvBankTransaction is a banking transaction performed in an investment
|
// InvBankTransaction is a banking transaction performed in an investment
|
||||||
@ -764,6 +845,7 @@ type InvPosition struct {
|
|||||||
// Position is an interface satisfied by all the other *Position types
|
// Position is an interface satisfied by all the other *Position types
|
||||||
type Position interface {
|
type Position interface {
|
||||||
PositionType() string
|
PositionType() string
|
||||||
|
InvPosition() InvPosition
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebtPosition represents a position held in a debt security
|
// DebtPosition represents a position held in a debt security
|
||||||
@ -777,6 +859,11 @@ func (p DebtPosition) PositionType() string {
|
|||||||
return "POSDEBT"
|
return "POSDEBT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvPosition returns InvPos
|
||||||
|
func (p DebtPosition) InvPosition() InvPosition {
|
||||||
|
return p.InvPos
|
||||||
|
}
|
||||||
|
|
||||||
// MFPosition represents a position held in a mutual fund
|
// MFPosition represents a position held in a mutual fund
|
||||||
type MFPosition struct {
|
type MFPosition struct {
|
||||||
XMLName xml.Name `xml:"POSMF"`
|
XMLName xml.Name `xml:"POSMF"`
|
||||||
@ -792,6 +879,11 @@ func (p MFPosition) PositionType() string {
|
|||||||
return "POSMF"
|
return "POSMF"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvPosition returns InvPos
|
||||||
|
func (p MFPosition) InvPosition() InvPosition {
|
||||||
|
return p.InvPos
|
||||||
|
}
|
||||||
|
|
||||||
// OptPosition represents a position held in an option
|
// OptPosition represents a position held in an option
|
||||||
type OptPosition struct {
|
type OptPosition struct {
|
||||||
XMLName xml.Name `xml:"POSOPT"`
|
XMLName xml.Name `xml:"POSOPT"`
|
||||||
@ -804,6 +896,11 @@ func (p OptPosition) PositionType() string {
|
|||||||
return "POSOPT"
|
return "POSOPT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvPosition returns InvPos
|
||||||
|
func (p OptPosition) InvPosition() InvPosition {
|
||||||
|
return p.InvPos
|
||||||
|
}
|
||||||
|
|
||||||
// OtherPosition represents a position held in a security type not covered by
|
// OtherPosition represents a position held in a security type not covered by
|
||||||
// the other *Position elements
|
// the other *Position elements
|
||||||
type OtherPosition struct {
|
type OtherPosition struct {
|
||||||
@ -816,6 +913,11 @@ func (p OtherPosition) PositionType() string {
|
|||||||
return "POSOTHER"
|
return "POSOTHER"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvPosition returns InvPos
|
||||||
|
func (p OtherPosition) InvPosition() InvPosition {
|
||||||
|
return p.InvPos
|
||||||
|
}
|
||||||
|
|
||||||
// StockPosition represents a position held in a stock
|
// StockPosition represents a position held in a stock
|
||||||
type StockPosition struct {
|
type StockPosition struct {
|
||||||
XMLName xml.Name `xml:"POSSTOCK"`
|
XMLName xml.Name `xml:"POSSTOCK"`
|
||||||
@ -830,6 +932,11 @@ func (p StockPosition) PositionType() string {
|
|||||||
return "POSSTOCK"
|
return "POSSTOCK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvPosition returns InvPos
|
||||||
|
func (p StockPosition) InvPosition() InvPosition {
|
||||||
|
return p.InvPos
|
||||||
|
}
|
||||||
|
|
||||||
// PositionList represents a list of positions held in securities in an
|
// PositionList represents a list of positions held in securities in an
|
||||||
// investment account
|
// investment account
|
||||||
type PositionList []Position
|
type PositionList []Position
|
||||||
@ -885,12 +992,12 @@ func (p *PositionList) UnmarshalXML(d *xml.Decoder, start xml.StartElement) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML handles marshalling a PositionList to an XML string
|
// MarshalXML handles marshalling a PositionList to an XML string
|
||||||
func (p *PositionList) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (p PositionList) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
invPosListElement := xml.StartElement{Name: xml.Name{Local: "INVPOSLIST"}}
|
invPosListElement := xml.StartElement{Name: xml.Name{Local: "INVPOSLIST"}}
|
||||||
if err := e.EncodeToken(invPosListElement); err != nil {
|
if err := e.EncodeToken(invPosListElement); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, position := range *p {
|
for _, position := range p {
|
||||||
start := xml.StartElement{Name: xml.Name{Local: position.PositionType()}}
|
start := xml.StartElement{Name: xml.Name{Local: position.PositionType()}}
|
||||||
switch pos := position.(type) {
|
switch pos := position.(type) {
|
||||||
case DebtPosition:
|
case DebtPosition:
|
||||||
@ -1190,12 +1297,12 @@ func (o *OOList) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML handles marshalling an OOList to an XML string
|
// MarshalXML handles marshalling an OOList to an XML string
|
||||||
func (o *OOList) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (o OOList) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
ooListElement := xml.StartElement{Name: xml.Name{Local: "INVOOLIST"}}
|
ooListElement := xml.StartElement{Name: xml.Name{Local: "INVOOLIST"}}
|
||||||
if err := e.EncodeToken(ooListElement); err != nil {
|
if err := e.EncodeToken(ooListElement); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, openorder := range *o {
|
for _, openorder := range o {
|
||||||
start := xml.StartElement{Name: xml.Name{Local: openorder.OrderType()}}
|
start := xml.StartElement{Name: xml.Name{Local: openorder.OrderType()}}
|
||||||
switch oo := openorder.(type) {
|
switch oo := openorder.(type) {
|
||||||
case OOBuyDebt:
|
case OOBuyDebt:
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package ofxgo
|
package ofxgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/aclindsa/xml"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aclindsa/xml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMarshalInvStatementRequest(t *testing.T) {
|
func TestMarshalInvStatementRequest(t *testing.T) {
|
||||||
@ -1866,3 +1867,84 @@ func TestUnmarshalOOList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
checkEqual(t, "OOList", reflect.ValueOf(&expected), reflect.ValueOf(&actual))
|
checkEqual(t, "OOList", reflect.ValueOf(&expected), reflect.ValueOf(&actual))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSecurityInfo(t *testing.T) {
|
||||||
|
secInfo := SecInfo{
|
||||||
|
Ticker: "ABC",
|
||||||
|
}
|
||||||
|
tests := []Security{
|
||||||
|
DebtInfo{SecInfo: secInfo},
|
||||||
|
MFInfo{SecInfo: secInfo},
|
||||||
|
OptInfo{SecInfo: secInfo},
|
||||||
|
OtherInfo{SecInfo: secInfo},
|
||||||
|
StockInfo{SecInfo: secInfo},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.SecurityType(), func(t *testing.T) {
|
||||||
|
info := tc.SecurityInfo()
|
||||||
|
if info.Ticker != secInfo.Ticker {
|
||||||
|
t.Errorf("got %v, want %v", info, secInfo)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvPosition(t *testing.T) {
|
||||||
|
invPos := InvPosition{
|
||||||
|
Memo: "stuff",
|
||||||
|
}
|
||||||
|
tests := []Position{
|
||||||
|
DebtPosition{InvPos: invPos},
|
||||||
|
MFPosition{InvPos: invPos},
|
||||||
|
OptPosition{InvPos: invPos},
|
||||||
|
OtherPosition{InvPos: invPos},
|
||||||
|
StockPosition{InvPos: invPos},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.PositionType(), func(t *testing.T) {
|
||||||
|
pos := tc.InvPosition()
|
||||||
|
if pos.Memo != invPos.Memo {
|
||||||
|
t.Errorf("got %v, want %v", pos, invPos)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvTransaction(t *testing.T) {
|
||||||
|
invTran := InvTran{
|
||||||
|
Memo: "stuff",
|
||||||
|
}
|
||||||
|
tests := []InvTransaction{
|
||||||
|
BuyDebt{InvBuy: InvBuy{InvTran: invTran}},
|
||||||
|
BuyMF{InvBuy: InvBuy{InvTran: invTran}},
|
||||||
|
BuyOpt{InvBuy: InvBuy{InvTran: invTran}},
|
||||||
|
BuyOther{InvBuy: InvBuy{InvTran: invTran}},
|
||||||
|
BuyStock{InvBuy: InvBuy{InvTran: invTran}},
|
||||||
|
ClosureOpt{InvTran: invTran},
|
||||||
|
Income{InvTran: invTran},
|
||||||
|
InvExpense{InvTran: invTran},
|
||||||
|
JrnlFund{InvTran: invTran},
|
||||||
|
JrnlSec{InvTran: invTran},
|
||||||
|
MarginInterest{InvTran: invTran},
|
||||||
|
Reinvest{InvTran: invTran},
|
||||||
|
RetOfCap{InvTran: invTran},
|
||||||
|
SellDebt{InvSell: InvSell{InvTran: invTran}},
|
||||||
|
SellMF{InvSell: InvSell{InvTran: invTran}},
|
||||||
|
SellOpt{InvSell: InvSell{InvTran: invTran}},
|
||||||
|
SellOther{InvSell: InvSell{InvTran: invTran}},
|
||||||
|
SellStock{InvSell: InvSell{InvTran: invTran}},
|
||||||
|
Split{InvTran: invTran},
|
||||||
|
Transfer{InvTran: invTran},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.TransactionType(), func(t *testing.T) {
|
||||||
|
tran := tc.InvTransaction()
|
||||||
|
if tran.Memo != invTran.Memo {
|
||||||
|
t.Errorf("got %v, want %v", tran, invTran)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
74
response.go
74
response.go
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/aclindsa/xml"
|
"github.com/aclindsa/xml"
|
||||||
@ -35,78 +36,75 @@ type Response struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (or *Response) readSGMLHeaders(r *bufio.Reader) error {
|
func (or *Response) readSGMLHeaders(r *bufio.Reader) error {
|
||||||
var seenHeader, seenVersion bool = false, false
|
b, err := r.ReadSlice('<')
|
||||||
for {
|
|
||||||
// Some financial institutions do not properly leave an empty line after the last header.
|
|
||||||
// Avoid attempting to read another header in that case.
|
|
||||||
next, err := r.Peek(1)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if next[0] == '<' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := r.ReadString('\n')
|
s := string(b)
|
||||||
|
err = r.UnreadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// r.ReadString leaves the '\n' on the end...
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
|
|
||||||
if len(line) == 0 {
|
// According to the latest OFX SGML spec (1.6), headers should be CRLF-separated
|
||||||
if seenHeader {
|
// and written as KEY:VALUE. However, some banks include a whitespace after the
|
||||||
break
|
// colon (KEY: VALUE), while others include no line breaks at all. The spec doesn't
|
||||||
} else {
|
// require a line break after the OFX headers, but it is allowed, and will be
|
||||||
continue
|
// optionally captured & discarded by the trailing `\s*`. Valid SGML headers must
|
||||||
}
|
// always be present in exactly this order, so a regular expression is acceptable.
|
||||||
}
|
headerExp := regexp.MustCompile(
|
||||||
header := strings.SplitN(line, ":", 2)
|
`^OFXHEADER:\s*(?P<OFXHEADER>\d+)\s*` +
|
||||||
if header == nil || len(header) != 2 {
|
`DATA:\s*(?P<DATA>[A-Z]+)\s*` +
|
||||||
|
`VERSION:\s*(?P<VERSION>\d+)\s*` +
|
||||||
|
`SECURITY:\s*(?P<SECURITY>[\w]+)\s*` +
|
||||||
|
`ENCODING:\s*(?P<ENCODING>[A-Z0-9-]+)\s*` +
|
||||||
|
`CHARSET:\s*(?P<CHARSET>[\w-]+)\s*` +
|
||||||
|
`COMPRESSION:\s*(?P<COMPRESSION>[A-Z]+)\s*` +
|
||||||
|
`OLDFILEUID:\s*(?P<OLDFILEUID>[\w-]+)\s*` +
|
||||||
|
`NEWFILEUID:\s*(?P<NEWFILEUID>[\w-]+)\s*<$`)
|
||||||
|
|
||||||
|
matches := headerExp.FindStringSubmatch(s)
|
||||||
|
if len(matches) == 0 {
|
||||||
return errors.New("OFX headers malformed")
|
return errors.New("OFX headers malformed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some OFX servers put a space after the colon
|
for i, name := range headerExp.SubexpNames() {
|
||||||
headervalue := strings.TrimSpace(header[1])
|
if i == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch header[0] {
|
headerValue := matches[i]
|
||||||
|
switch name {
|
||||||
case "OFXHEADER":
|
case "OFXHEADER":
|
||||||
if headervalue != "100" {
|
if headerValue != "100" {
|
||||||
return errors.New("OFXHEADER is not 100")
|
return errors.New("OFXHEADER is not 100")
|
||||||
}
|
}
|
||||||
seenHeader = true
|
|
||||||
case "DATA":
|
case "DATA":
|
||||||
if headervalue != "OFXSGML" {
|
if headerValue != "OFXSGML" {
|
||||||
return errors.New("OFX DATA header does not contain OFXSGML")
|
return errors.New("OFX DATA header does not contain OFXSGML")
|
||||||
}
|
}
|
||||||
case "VERSION":
|
case "VERSION":
|
||||||
err := or.Version.FromString(headervalue)
|
err := or.Version.FromString(headerValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
seenVersion = true
|
|
||||||
|
|
||||||
if or.Version > OfxVersion160 {
|
if or.Version > OfxVersion160 {
|
||||||
return errors.New("OFX VERSION > 160 in SGML header")
|
return errors.New("OFX VERSION > 160 in SGML header")
|
||||||
}
|
}
|
||||||
case "SECURITY":
|
case "SECURITY":
|
||||||
if headervalue != "NONE" {
|
if !(headerValue == "NONE" || headerValue == "TYPE1") {
|
||||||
return errors.New("OFX SECURITY header not NONE")
|
return errors.New("OFX SECURITY header must be NONE or TYPE1")
|
||||||
}
|
}
|
||||||
case "COMPRESSION":
|
case "COMPRESSION":
|
||||||
if headervalue != "NONE" {
|
if headerValue != "NONE" {
|
||||||
return errors.New("OFX COMPRESSION header not NONE")
|
return errors.New("OFX COMPRESSION header not NONE")
|
||||||
}
|
}
|
||||||
case "ENCODING", "CHARSET", "OLDFILEUID", "NEWFILEUID":
|
case "ENCODING", "CHARSET", "OLDFILEUID", "NEWFILEUID":
|
||||||
// TODO check/handle these headers?
|
// TODO: check/handle these headers?
|
||||||
default:
|
|
||||||
return errors.New("Invalid OFX header: " + header[0])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !seenVersion {
|
|
||||||
return errors.New("OFX VERSION header missing")
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,8 +176,7 @@ func TestValidSamples(t *testing.T) {
|
|||||||
|
|
||||||
func TestInvalidResponse(t *testing.T) {
|
func TestInvalidResponse(t *testing.T) {
|
||||||
// in this example, the severity is invalid due to mixed upper and lower case letters
|
// in this example, the severity is invalid due to mixed upper and lower case letters
|
||||||
const invalidResponse = `
|
const invalidResponse = `OFXHEADER:100
|
||||||
OFXHEADER:100
|
|
||||||
DATA:OFXSGML
|
DATA:OFXSGML
|
||||||
VERSION:102
|
VERSION:102
|
||||||
SECURITY:NONE
|
SECURITY:NONE
|
||||||
|
1
samples/busted_responses/wellsfargo.qfx
Normal file
1
samples/busted_responses/wellsfargo.qfx
Normal file
@ -0,0 +1 @@
|
|||||||
|
OFXHEADER:100DATA:OFXSGMLVERSION:102SECURITY:NONEENCODING:USASCIICHARSET:1252COMPRESSION:NONEOLDFILEUID:NONENEWFILEUID:NONE<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0<SEVERITY>INFO<MESSAGE>SUCCESS</STATUS><DTSERVER>20210102211014.201[-8:PST]<LANGUAGE>ENG<FI><ORG>WF<FID>1000</FI><SESSCOOKIE>abc-123<INTU.BID>1000<INTU.USERID>jane_doe</SONRS></SIGNONMSGSRSV1><BANKMSGSRSV1><STMTTRNRS><TRNUID>0<STATUS><CODE>0<SEVERITY>INFO<MESSAGE>SUCCESS</STATUS><STMTRS><CURDEF>USD<BANKACCTFROM><BANKID>123456789<ACCTID>9876543210<ACCTTYPE>CHECKING</BANKACCTFROM><BANKTRANLIST><DTSTART>20201201120000.000[-8:PST]<DTEND>20201231120000.000[-8:PST]<STMTTRN><TRNTYPE>DIRECTDEBIT<DTPOSTED>20201201120000.000[-8:PST]<TRNAMT>-12.34<FITID>202012011<NAME>AE Visa Card AE EPAY<MEMO> XXXXX1234</STMTTRN></BANKTRANLIST><LEDGERBAL><BALAMT>123.45<DTASOF>20201231120000.000[-8:PST]</LEDGERBAL><AVAILBAL><BALAMT>123.45<DTASOF>20201231120000.000[-8:PST]</AVAILBAL></STMTRS></STMTTRNRS></BANKMSGSRSV1></OFX>
|
75
samples/valid_responses/moneymrkt1_v103_TYPE1.ofx
Normal file
75
samples/valid_responses/moneymrkt1_v103_TYPE1.ofx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
OFXHEADER:100
|
||||||
|
DATA:OFXSGML
|
||||||
|
VERSION:103
|
||||||
|
SECURITY:TYPE1
|
||||||
|
ENCODING:USASCII
|
||||||
|
CHARSET:1252
|
||||||
|
COMPRESSION:NONE
|
||||||
|
OLDFILEUID:NONE
|
||||||
|
NEWFILEUID:NONE
|
||||||
|
|
||||||
|
<OFX>
|
||||||
|
<SIGNONMSGSRSV1><SONRS>
|
||||||
|
<STATUS>
|
||||||
|
<CODE>0
|
||||||
|
<SEVERITY>INFO
|
||||||
|
</STATUS>
|
||||||
|
<DTSERVER>20170407001840.607[0:GMT]
|
||||||
|
<LANGUAGE>ENG
|
||||||
|
<FI>
|
||||||
|
<ORG>UJKDO
|
||||||
|
<FID>3534
|
||||||
|
</FI>
|
||||||
|
</SONRS>
|
||||||
|
</SIGNONMSGSRSV1>
|
||||||
|
<BANKMSGSRSV1>
|
||||||
|
<STMTTRNRS>
|
||||||
|
<TRNUID>e1707dfd-695d-4451-8d9c-0e142fdc456a
|
||||||
|
<STATUS>
|
||||||
|
<CODE>0
|
||||||
|
<SEVERITY>INFO
|
||||||
|
</STATUS>
|
||||||
|
<STMTRS>
|
||||||
|
<CURDEF>USD
|
||||||
|
<BANKACCTFROM>
|
||||||
|
<BANKID>598813374
|
||||||
|
<ACCTID>35342483513
|
||||||
|
<ACCTTYPE>MONEYMRKT
|
||||||
|
</BANKACCTFROM>
|
||||||
|
<BANKTRANLIST>
|
||||||
|
<DTSTART>20170107011841.262[0:GMT]
|
||||||
|
<DTEND>20170407001841.262[0:GMT]
|
||||||
|
<STMTTRN>
|
||||||
|
<TRNTYPE>CREDIT
|
||||||
|
<DTPOSTED>20170117120000.000[0:GMT]
|
||||||
|
<TRNAMT>-995.4190396554627
|
||||||
|
<FITID>2fb2640c-cee3-4643-8ba3-ea21a4d18954
|
||||||
|
<NAME>Dividend Earned
|
||||||
|
</STMTTRN>
|
||||||
|
<STMTTRN>
|
||||||
|
<TRNTYPE>CREDIT
|
||||||
|
<DTPOSTED>20170215120000.000[0:GMT]
|
||||||
|
<TRNAMT>788.5385340523635
|
||||||
|
<FITID>c9d856df-339c-47c6-9f6a-8c2e2910f62e
|
||||||
|
<NAME>Dividend Earned
|
||||||
|
</STMTTRN>
|
||||||
|
<STMTTRN>
|
||||||
|
<TRNTYPE>CREDIT
|
||||||
|
<DTPOSTED>20170315120000.000[0:GMT]
|
||||||
|
<TRNAMT>3070.1328011762807
|
||||||
|
<FITID>1107ace0-048b-4c0c-b5f3-45b6be4cd71d
|
||||||
|
<NAME>Dividend Earned
|
||||||
|
</STMTTRN>
|
||||||
|
</BANKTRANLIST>
|
||||||
|
<LEDGERBAL>
|
||||||
|
<BALAMT>2607.1664944585727
|
||||||
|
<DTASOF>20170407001841.262[0:GMT]
|
||||||
|
</LEDGERBAL>
|
||||||
|
<AVAILBAL>
|
||||||
|
<BALAMT>4503.683156768119
|
||||||
|
<DTASOF>20170407001841.262[0:GMT]
|
||||||
|
</AVAILBAL>
|
||||||
|
</STMTRS>
|
||||||
|
</STMTTRNRS>
|
||||||
|
</BANKMSGSRSV1>
|
||||||
|
</OFX>
|
26
seclist.go
26
seclist.go
@ -94,6 +94,7 @@ func (r *SecListResponse) Type() messageType {
|
|||||||
// securities for SecurityList
|
// securities for SecurityList
|
||||||
type Security interface {
|
type Security interface {
|
||||||
SecurityType() string
|
SecurityType() string
|
||||||
|
SecurityInfo() SecInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecInfo represents the generic information about a security. It is included
|
// SecInfo represents the generic information about a security. It is included
|
||||||
@ -136,6 +137,11 @@ func (i DebtInfo) SecurityType() string {
|
|||||||
return "DEBTINFO"
|
return "DEBTINFO"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecurityInfo returns SecInfo
|
||||||
|
func (i DebtInfo) SecurityInfo() SecInfo {
|
||||||
|
return i.SecInfo
|
||||||
|
}
|
||||||
|
|
||||||
// AssetPortion represents the percentage of a mutual fund with the given asset
|
// AssetPortion represents the percentage of a mutual fund with the given asset
|
||||||
// classification
|
// classification
|
||||||
type AssetPortion struct {
|
type AssetPortion struct {
|
||||||
@ -169,6 +175,11 @@ func (i MFInfo) SecurityType() string {
|
|||||||
return "MFINFO"
|
return "MFINFO"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecurityInfo returns SecInfo
|
||||||
|
func (i MFInfo) SecurityInfo() SecInfo {
|
||||||
|
return i.SecInfo
|
||||||
|
}
|
||||||
|
|
||||||
// OptInfo provides information about an option
|
// OptInfo provides information about an option
|
||||||
type OptInfo struct {
|
type OptInfo struct {
|
||||||
XMLName xml.Name `xml:"OPTINFO"`
|
XMLName xml.Name `xml:"OPTINFO"`
|
||||||
@ -187,6 +198,11 @@ func (i OptInfo) SecurityType() string {
|
|||||||
return "OPTINFO"
|
return "OPTINFO"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecurityInfo returns SecInfo
|
||||||
|
func (i OptInfo) SecurityInfo() SecInfo {
|
||||||
|
return i.SecInfo
|
||||||
|
}
|
||||||
|
|
||||||
// OtherInfo provides information about a security type not covered by the
|
// OtherInfo provides information about a security type not covered by the
|
||||||
// other *Info elements
|
// other *Info elements
|
||||||
type OtherInfo struct {
|
type OtherInfo struct {
|
||||||
@ -202,6 +218,11 @@ func (i OtherInfo) SecurityType() string {
|
|||||||
return "OTHERINFO"
|
return "OTHERINFO"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecurityInfo returns SecInfo
|
||||||
|
func (i OtherInfo) SecurityInfo() SecInfo {
|
||||||
|
return i.SecInfo
|
||||||
|
}
|
||||||
|
|
||||||
// StockInfo provides information about a security type
|
// StockInfo provides information about a security type
|
||||||
type StockInfo struct {
|
type StockInfo struct {
|
||||||
XMLName xml.Name `xml:"STOCKINFO"`
|
XMLName xml.Name `xml:"STOCKINFO"`
|
||||||
@ -218,6 +239,11 @@ func (i StockInfo) SecurityType() string {
|
|||||||
return "STOCKINFO"
|
return "STOCKINFO"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecurityInfo returns SecInfo
|
||||||
|
func (i StockInfo) SecurityInfo() SecInfo {
|
||||||
|
return i.SecInfo
|
||||||
|
}
|
||||||
|
|
||||||
// SecurityList is a container for Security objects containaing information
|
// SecurityList is a container for Security objects containaing information
|
||||||
// about securities
|
// about securities
|
||||||
type SecurityList struct {
|
type SecurityList struct {
|
||||||
|
@ -14,6 +14,7 @@ type SignonRequest struct {
|
|||||||
UserID String `xml:"USERID"`
|
UserID String `xml:"USERID"`
|
||||||
UserPass String `xml:"USERPASS,omitempty"`
|
UserPass String `xml:"USERPASS,omitempty"`
|
||||||
UserKey String `xml:"USERKEY,omitempty"`
|
UserKey String `xml:"USERKEY,omitempty"`
|
||||||
|
GenUserKey Boolean `xml:"GENUSERKEY,omitempty"`
|
||||||
Language String `xml:"LANGUAGE"` // Defaults to ENG
|
Language String `xml:"LANGUAGE"` // Defaults to ENG
|
||||||
Org String `xml:"FI>ORG"`
|
Org String `xml:"FI>ORG"`
|
||||||
Fid String `xml:"FI>FID"`
|
Fid String `xml:"FI>FID"`
|
||||||
|
10
types.go
10
types.go
@ -76,7 +76,7 @@ func (a Amount) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML marshals an Amount to SGML/XML
|
// MarshalXML marshals an Amount to SGML/XML
|
||||||
func (a *Amount) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (a Amount) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
return e.EncodeElement(a.String(), start)
|
return e.EncodeElement(a.String(), start)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ func (od Date) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML marshals a Date to XML
|
// MarshalXML marshals a Date to XML
|
||||||
func (od *Date) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (od Date) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
return e.EncodeElement(od.String(), start)
|
return e.EncodeElement(od.String(), start)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,8 +260,8 @@ func (ob *Boolean) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML marshals a Boolean to XML
|
// MarshalXML marshals a Boolean to XML
|
||||||
func (ob *Boolean) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (ob Boolean) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
if *ob {
|
if ob {
|
||||||
return e.EncodeElement("Y", start)
|
return e.EncodeElement("Y", start)
|
||||||
}
|
}
|
||||||
return e.EncodeElement("N", start)
|
return e.EncodeElement("N", start)
|
||||||
@ -358,7 +358,7 @@ func (c *CurrSymbol) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML marshals a CurrSymbol to SGML/XML
|
// MarshalXML marshals a CurrSymbol to SGML/XML
|
||||||
func (c *CurrSymbol) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (c CurrSymbol) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
return e.EncodeElement(c.String(), start)
|
return e.EncodeElement(c.String(), start)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,13 @@ func TestMarshalAmount(t *testing.T) {
|
|||||||
marshalHelper(t, "-768276587425", &a)
|
marshalHelper(t, "-768276587425", &a)
|
||||||
a.SetFrac64(1, 12)
|
a.SetFrac64(1, 12)
|
||||||
marshalHelper(t, "0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", &a)
|
marshalHelper(t, "0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", &a)
|
||||||
|
|
||||||
|
type AmountStruct struct {
|
||||||
|
A Amount
|
||||||
|
}
|
||||||
|
var as AmountStruct
|
||||||
|
as.A.SetFrac64(1, 8)
|
||||||
|
marshalHelper(t, "<A>0.125</A>", as)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalAmount(t *testing.T) {
|
func TestUnmarshalAmount(t *testing.T) {
|
||||||
@ -155,7 +162,7 @@ func TestAmountEqual(t *testing.T) {
|
|||||||
func TestMarshalDate(t *testing.T) {
|
func TestMarshalDate(t *testing.T) {
|
||||||
var d *Date
|
var d *Date
|
||||||
UTC := time.FixedZone("UTC", 0)
|
UTC := time.FixedZone("UTC", 0)
|
||||||
GMT_nodesc := time.FixedZone("", 0)
|
GMTNodesc := time.FixedZone("", 0)
|
||||||
EST := time.FixedZone("EST", -5*60*60)
|
EST := time.FixedZone("EST", -5*60*60)
|
||||||
NPT := time.FixedZone("NPT", (5*60+45)*60)
|
NPT := time.FixedZone("NPT", (5*60+45)*60)
|
||||||
IST := time.FixedZone("IST", (5*60+30)*60)
|
IST := time.FixedZone("IST", (5*60+30)*60)
|
||||||
@ -183,8 +190,15 @@ func TestMarshalDate(t *testing.T) {
|
|||||||
marshalHelper(t, "20170314000026.053[-3.50:NST]", d)
|
marshalHelper(t, "20170314000026.053[-3.50:NST]", d)
|
||||||
|
|
||||||
// Time zone without textual description
|
// Time zone without textual description
|
||||||
d = NewDate(2017, 3, 14, 15, 9, 26, 53*1000*1000, GMT_nodesc)
|
d = NewDate(2017, 3, 14, 15, 9, 26, 53*1000*1000, GMTNodesc)
|
||||||
marshalHelper(t, "20170314150926.053[0]", d)
|
marshalHelper(t, "20170314150926.053[0]", d)
|
||||||
|
|
||||||
|
type DateStruct struct {
|
||||||
|
D Date
|
||||||
|
}
|
||||||
|
d = NewDateGMT(2017, 3, 14, 15, 9, 26, 53*1000*1000)
|
||||||
|
ds := DateStruct{D: *d}
|
||||||
|
marshalHelper(t, "<D>20170314150926.053[0:GMT]</D>", ds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalDate(t *testing.T) {
|
func TestUnmarshalDate(t *testing.T) {
|
||||||
@ -195,7 +209,7 @@ func TestUnmarshalDate(t *testing.T) {
|
|||||||
NPT := time.FixedZone("NPT", (5*60+45)*60)
|
NPT := time.FixedZone("NPT", (5*60+45)*60)
|
||||||
IST := time.FixedZone("IST", (5*60+30)*60)
|
IST := time.FixedZone("IST", (5*60+30)*60)
|
||||||
NST := time.FixedZone("NST", -(3*60+30)*60)
|
NST := time.FixedZone("NST", -(3*60+30)*60)
|
||||||
NST_nodesc := time.FixedZone("", -(3*60+30)*60)
|
NSTNodesc := time.FixedZone("", -(3*60+30)*60)
|
||||||
|
|
||||||
eq := func(a, b interface{}) bool {
|
eq := func(a, b interface{}) bool {
|
||||||
if dateA, ok := a.(*Date); ok {
|
if dateA, ok := a.(*Date); ok {
|
||||||
@ -245,7 +259,7 @@ func TestUnmarshalDate(t *testing.T) {
|
|||||||
d = NewDate(2017, 3, 14, 15, 9, 26, 53*1000*1000, GMT)
|
d = NewDate(2017, 3, 14, 15, 9, 26, 53*1000*1000, GMT)
|
||||||
unmarshalHelper2(t, "20170314150926.053[0]", d, &overwritten, eq)
|
unmarshalHelper2(t, "20170314150926.053[0]", d, &overwritten, eq)
|
||||||
// but not for others:
|
// but not for others:
|
||||||
d = NewDate(2017, 3, 14, 0, 0, 26, 53*1000*1000, NST_nodesc)
|
d = NewDate(2017, 3, 14, 0, 0, 26, 53*1000*1000, NSTNodesc)
|
||||||
unmarshalHelper2(t, "20170314000026.053[-3.50]", d, &overwritten, eq)
|
unmarshalHelper2(t, "20170314000026.053[-3.50]", d, &overwritten, eq)
|
||||||
|
|
||||||
// Make sure we handle poorly-formatted dates (from Vanguard)
|
// Make sure we handle poorly-formatted dates (from Vanguard)
|
||||||
@ -316,11 +330,24 @@ func TestUnmarshalString(t *testing.T) {
|
|||||||
unmarshalHelper(t, "Some Name\n ", &s, &overwritten)
|
unmarshalHelper(t, "Some Name\n ", &s, &overwritten)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStringString(t *testing.T) {
|
||||||
|
var s String = "foobar"
|
||||||
|
if s.String() != "foobar" {
|
||||||
|
t.Fatalf("Unexpected result when returning String.String(): %s\n", s.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMarshalBoolean(t *testing.T) {
|
func TestMarshalBoolean(t *testing.T) {
|
||||||
var b Boolean = true
|
var b Boolean = true
|
||||||
marshalHelper(t, "Y", &b)
|
marshalHelper(t, "Y", &b)
|
||||||
b = false
|
b = false
|
||||||
marshalHelper(t, "N", &b)
|
marshalHelper(t, "N", &b)
|
||||||
|
|
||||||
|
type BooleanStruct struct {
|
||||||
|
B Boolean
|
||||||
|
}
|
||||||
|
bs := BooleanStruct{B: true}
|
||||||
|
marshalHelper(t, "<B>Y</B>", bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalBoolean(t *testing.T) {
|
func TestUnmarshalBoolean(t *testing.T) {
|
||||||
@ -333,6 +360,17 @@ func TestUnmarshalBoolean(t *testing.T) {
|
|||||||
unmarshalHelper(t, "N\n \t", &b, &overwritten)
|
unmarshalHelper(t, "N\n \t", &b, &overwritten)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStringBoolean(t *testing.T) {
|
||||||
|
var b Boolean = true
|
||||||
|
if b.String() != "true" {
|
||||||
|
t.Fatalf("Unexpected string for Boolean.String() for true: %s\n", b.String())
|
||||||
|
}
|
||||||
|
b = false
|
||||||
|
if b.String() != "false" {
|
||||||
|
t.Fatalf("Unexpected string for Boolean.String() for false: %s\n", b.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMarshalUID(t *testing.T) {
|
func TestMarshalUID(t *testing.T) {
|
||||||
var u UID = "d1cf3d3d-9ef9-4a97-b180-81706829cb04"
|
var u UID = "d1cf3d3d-9ef9-4a97-b180-81706829cb04"
|
||||||
marshalHelper(t, "d1cf3d3d-9ef9-4a97-b180-81706829cb04", &u)
|
marshalHelper(t, "d1cf3d3d-9ef9-4a97-b180-81706829cb04", &u)
|
||||||
@ -394,6 +432,12 @@ func TestRandomUID(t *testing.T) {
|
|||||||
func TestMarshalCurrSymbol(t *testing.T) {
|
func TestMarshalCurrSymbol(t *testing.T) {
|
||||||
c, _ := NewCurrSymbol("USD")
|
c, _ := NewCurrSymbol("USD")
|
||||||
marshalHelper(t, "USD", &c)
|
marshalHelper(t, "USD", &c)
|
||||||
|
|
||||||
|
type CurrSymbolStruct struct {
|
||||||
|
CS CurrSymbol
|
||||||
|
}
|
||||||
|
css := CurrSymbolStruct{CS: *c}
|
||||||
|
marshalHelper(t, "<CS>USD</CS>", css)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalCurrSymbol(t *testing.T) {
|
func TestUnmarshalCurrSymbol(t *testing.T) {
|
||||||
|
@ -15,7 +15,7 @@ type VanguardClient struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewVanguardClient returns a Client interface configured to handle Vanguard's
|
// NewVanguardClient returns a Client interface configured to handle Vanguard's
|
||||||
// brand of idiosyncracy
|
// brand of idiosyncrasy
|
||||||
func NewVanguardClient(bc *BasicClient) Client {
|
func NewVanguardClient(bc *BasicClient) Client {
|
||||||
return &VanguardClient{bc}
|
return &VanguardClient{bc}
|
||||||
}
|
}
|
||||||
@ -47,6 +47,8 @@ func rawRequestCookies(URL string, r io.Reader, cookies []*http.Cookie) (*http.R
|
|||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestNoParse marshals a Request to XML, makes an HTTP request, and returns
|
||||||
|
// the raw HTTP response
|
||||||
func (c *VanguardClient) RequestNoParse(r *Request) (*http.Response, error) {
|
func (c *VanguardClient) RequestNoParse(r *Request) (*http.Response, error) {
|
||||||
r.SetClientFields(c)
|
r.SetClientFields(c)
|
||||||
|
|
||||||
@ -62,7 +64,7 @@ func (c *VanguardClient) RequestNoParse(r *Request) (*http.Response, error) {
|
|||||||
// Fortunately, the initial response contains the cookie we need, so if we
|
// Fortunately, the initial response contains the cookie we need, so if we
|
||||||
// detect an empty response with cookies set that didn't have any errors,
|
// detect an empty response with cookies set that didn't have any errors,
|
||||||
// re-try the request while sending their cookies back to them.
|
// re-try the request while sending their cookies back to them.
|
||||||
if err == nil && response.ContentLength <= 0 && len(response.Cookies()) > 0 {
|
if response != nil && response.ContentLength <= 0 && len(response.Cookies()) > 0 {
|
||||||
b, err = r.Marshal()
|
b, err = r.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -74,6 +76,8 @@ func (c *VanguardClient) RequestNoParse(r *Request) (*http.Response, error) {
|
|||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request marshals a Request to XML, makes an HTTP request, and then
|
||||||
|
// unmarshals the response into a Response object.
|
||||||
func (c *VanguardClient) Request(r *Request) (*Response, error) {
|
func (c *VanguardClient) Request(r *Request) (*Response, error) {
|
||||||
return clientRequest(c, r)
|
return clientRequest(c, r)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user