mirror of
https://github.com/aclindsa/ofxgo.git
synced 2024-10-30 05:20:05 -04:00
254 lines
9.9 KiB
Python
Executable File
254 lines
9.9 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
enums = {
|
|
# OFX spec version
|
|
"OfxVersion": (["102", "103", "151", "160", "200", "201", "202", "203", "210", "211", "220"], "the OFX specification version in use"),
|
|
|
|
# Bank/general
|
|
"AcctType": (["Checking", "Savings", "MoneyMrkt", "CreditLine", "CD"], "types of bank accounts"),
|
|
"TrnType": (["Credit", "Debit", "Int", "Div", "Fee", "SrvChg", "Dep", "ATM", "POS", "Xfer", "Check", "Payment", "Cash", "DirectDep", "DirectDebit", "RepeatPmt", "Hold", "Other"], "types of transactions. INT, ATM, and POS depend on the signage of the account."),
|
|
"ImageType": (["Statement", "Transaction", "Tax"], "what this image contains"),
|
|
"ImageRefType": (["Opaque", "URL", "FormURL"], "the type of reference to the image"),
|
|
"CheckSup": (["FrontOnly", "BackOnly", "FrontAndBack"], "what portions of the check this image contains"),
|
|
"CorrectAction": (["Delete", "Replace"], "whether this transaction correction replaces or deletes the transaction matching its CORRECTFITID"),
|
|
"BalType": (["Dollar", "Percent", "Number"], "how this BAL's VALUE field should be interpreted"),
|
|
|
|
# InvStmt
|
|
"Inv401kSource": (["PreTax", "AfterTax", "Match", "ProfitSharing", "Rollover", "OtherVest", "OtherNonVest"], "the source of money used for this security in a 401(k) account. Default if not present is OTHERNONVEST. The following cash source types are subject to vesting: MATCH, PROFITSHARING, and OTHERVEST."),
|
|
"SubAcctType": (["Cash", "Margin", "Short", "Other"], "the sub-account type for a source and/or destination of a transaction. Used in fields named SubAcctFrom, SubAcctTo, SubAcctSec, SubAcctFund, HeldInAcct."),
|
|
"BuyType": (["Buy", "BuyToCover"], "types of purchases"),
|
|
"OptAction": (["Exercise", "Assign", "Expire"], "types of actions for options"),
|
|
"TferAction": (["In", "Out"], "whether the transfer is into or out of this account"),
|
|
"PosType": (["Long", "Short"], "position type"),
|
|
"Secured": (["Naked", "Covered"], "how an option is secured"),
|
|
"Duration": (["Day", "GoodTilCancel", "Immediate"], "how long the investment order is good for"),
|
|
"Restriction": (["AllOrNone", "MinUnits", "None"], "a special restriction on an investment order"),
|
|
"UnitType": (["Shares", "Currency"], "type of the UNITS value"),
|
|
"OptBuyType": (["BuyToOpen", "BuyToClose"], "types of purchases for options"),
|
|
"SellType": (["Sell", "SellShort"], "types of sales"),
|
|
"LoanPmtFreq": (["Weekly", "Biweekly", "TwiceMonthly", "Monthly", "FourWeeks", "BiMonthly", "Quarterly", "Semiannually", "Annually", "Other"], "the frequency of loan payments"),
|
|
"IncomeType": (["CGLong", "CGShort", "Div", "Interest", "Misc"], "types of investment income"),
|
|
"SellReason": (["Call", "Sell", "Maturity"], "the reason the sell of a debt security was generated: CALL (the debt was called), SELL (the debt was sold), MATURITY (the debt reached maturity)"),
|
|
"OptSellType": (["SellToClose", "SellToOpen"], "types of sales for options"),
|
|
"RelType": (["Spread", "Straddle", "None", "Other"], "related option transaction types"),
|
|
|
|
# Prof
|
|
"CharType": (["AlphaOnly", "NumericOnly", "AlphaOrNumeric", "AlphaAndNumeric"], "types of characters allowed in password"),
|
|
"SyncMode": (["Full", "Lite"], "data synchronization mode supported (see OFX spec for more details)"),
|
|
"OfxSec": (["None", "Type 1"], "the type of application-level security required for the message set"),
|
|
|
|
# SecList
|
|
"DebtType": (["Coupon", "Zero"], "debt type"),
|
|
"DebtClass": (["Treasury", "Municipal", "Corporate", "Other"], "the class of debt"),
|
|
"CouponFreq": (["Monthly", "Quarterly", "Semiannual", "Annual", "Other"], "when debt coupons mature"),
|
|
"CallType": (["Call", "Put", "Prefund", "Maturity"], "type of next call (for a debt)"),
|
|
"AssetClass": (["DomesticBond", "IntlBond", "LargeStock", "SmallStock", "IntlStock", "MoneyMrkt", "Other"], "type of asset classes"),
|
|
"MfType": (["OpenEnd", "CloseEnd", "Other"], "types of mutual funds"),
|
|
"OptType": (["Put", "Call"], "whether the option is a PUT or a CALL"),
|
|
"StockType": (["Common", "Preferred", "Convertible", "Other"], "types of stock"),
|
|
|
|
# Signup
|
|
"HolderType": (["Individual", "Joint", "Custodial", "Trust", "Other"], "how the account is held"),
|
|
"AcctClassification": (["Personal", "Business", "Corporate", "Other"], "the type of an account"),
|
|
"SvcStatus": (["Avail", "Pend", "Active"], "the status of the account: AVAIL = Available, but not yet requested, PEND = Requested, but not yet available, ACTIVE = In use"),
|
|
"UsProductType": (["401K", "403B", "IRA", "KEOGH", "Other", "SARSEP", "Simple", "Normal", "TDA", "Trust", "UGMA"], "type of investment account (in the US)"),
|
|
}
|
|
|
|
header = """package ofxgo
|
|
|
|
/*
|
|
* Do not edit this file by hand. It is auto-generated by calling `go generate`.
|
|
* To make changes, edit generate_constants.py, re-run `go generate`, and check
|
|
* in the result.
|
|
*/
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/aclindsa/xml"
|
|
)
|
|
"""
|
|
|
|
template = """
|
|
type {enumLower} uint
|
|
|
|
// {enum}* constants represent {comment}
|
|
const (
|
|
{constNames})
|
|
|
|
var {enumLower}s = [...]string{{"{upperValueString}"}}
|
|
|
|
func (e {enumLower}) Valid() bool {{
|
|
// This check is mostly out of paranoia, ensuring e != 0 should be
|
|
// sufficient
|
|
return e >= {firstValue} && e <= {lastValue}
|
|
}}
|
|
|
|
func (e {enumLower}) String() string {{
|
|
if e.Valid() {{
|
|
return {enumLower}s[e-1]
|
|
}}
|
|
return fmt.Sprintf("invalid {enumLower} (%d)", e)
|
|
}}
|
|
|
|
func (e *{enumLower}) FromString(in string) error {{
|
|
value := strings.TrimSpace(in)
|
|
|
|
for i, s := range {enumLower}s {{
|
|
if s == value {{
|
|
*e = {enumLower}(i + 1)
|
|
return nil
|
|
}}
|
|
}}
|
|
*e = 0
|
|
return errors.New("Invalid {enum}: \\\"" + in + "\\\"")
|
|
}}
|
|
|
|
func (e *{enumLower}) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {{
|
|
var value string
|
|
err := d.DecodeElement(&value, &start)
|
|
if err != nil {{
|
|
return err
|
|
}}
|
|
|
|
return e.FromString(value)
|
|
}}
|
|
|
|
func (e {enumLower}) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {{
|
|
if !e.Valid() {{
|
|
return nil
|
|
}}
|
|
enc.EncodeElement({enumLower}s[e-1], start)
|
|
return nil
|
|
}}
|
|
|
|
// New{enum} returns returns an 'enum' value of type {enumLower} given its
|
|
// string representation
|
|
func New{enum}(s string) ({enumLower}, error) {{
|
|
var e {enumLower}
|
|
err := e.FromString(s)
|
|
if err != nil {{
|
|
return 0, err
|
|
}}
|
|
return e, nil
|
|
}}
|
|
"""
|
|
|
|
with open("constants.go", 'w') as f:
|
|
f.write(header)
|
|
|
|
for enum in enums:
|
|
enumLower = enum[:1].lower() + enum[1:].replace(" ", "")
|
|
firstValue = enum+enums[enum][0][0].replace(" ", "")
|
|
lastValue = enum+enums[enum][0][-1].replace(" ", "")
|
|
|
|
comment = enums[enum][1]
|
|
|
|
constNames = "\t{firstValue} {enumLower} = 1 + iota\n".format(
|
|
enum=enum,
|
|
firstValue=firstValue,
|
|
enumLower=enumLower)
|
|
for value in enums[enum][0][1:]:
|
|
constNames += "\t{enum}{value}\n".format(
|
|
enum=enum,
|
|
value=value.replace(" ", ""))
|
|
|
|
upperValueString = "\", \"".join([s.upper() for s in enums[enum][0]])
|
|
|
|
f.write(template.format(enum=enum,
|
|
enumLower=enumLower,
|
|
comment=comment,
|
|
firstValue=firstValue,
|
|
lastValue=lastValue,
|
|
constNames=constNames,
|
|
upperValueString=upperValueString))
|
|
|
|
test_header = """package ofxgo
|
|
|
|
/*
|
|
* Do not edit this file by hand. It is auto-generated by calling `go generate`.
|
|
* To make changes, edit generate_constants.py, re-run `go generate`, and check
|
|
* in the result.
|
|
*/
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/aclindsa/xml"
|
|
)
|
|
"""
|
|
|
|
test_template = """
|
|
func Test{enum}(t *testing.T) {{
|
|
e, err := New{enum}("{firstValueUpper}")
|
|
if err != nil {{
|
|
t.Fatalf("Unexpected error creating new {enum} from string \\\"{firstValueUpper}\\\"\\n")
|
|
}}
|
|
if !e.Valid() {{
|
|
t.Fatalf("{enum} unexpectedly invalid\\n")
|
|
}}
|
|
err = e.FromString("{lastValueUpper}")
|
|
if err != nil {{
|
|
t.Fatalf("Unexpected error on {enum}.FromString(\\\"{lastValueUpper}\\\")\\n")
|
|
}}
|
|
if e.String() != "{lastValueUpper}" {{
|
|
t.Fatalf("{enum}.String() expected to be \\\"{lastValueUpper}\\\"\\n")
|
|
}}
|
|
|
|
marshalHelper(t, "{lastValueUpper}", &e)
|
|
|
|
overwritten, err := New{enum}("THISWILLNEVERBEAVALIDENUMSTRING")
|
|
if err == nil {{
|
|
t.Fatalf("Expected error creating new {enum} from string \\\"THISWILLNEVERBEAVALIDENUMSTRING\\\"\\n")
|
|
}}
|
|
if overwritten.Valid() {{
|
|
t.Fatalf("{enum} created with string \\\"THISWILLNEVERBEAVALIDENUMSTRING\\\" should not be valid\\n")
|
|
}}
|
|
if !strings.Contains(strings.ToLower(overwritten.String()), "invalid") {{
|
|
t.Fatalf("{enum} created with string \\\"THISWILLNEVERBEAVALIDENUMSTRING\\\" should not return valid string from String()\\n")
|
|
}}
|
|
|
|
b, err := xml.Marshal(&overwritten)
|
|
if err != nil {{
|
|
t.Fatalf("Unexpected error on xml.Marshal({enum}): %s\\n", err)
|
|
}}
|
|
if string(b) != "" {{
|
|
t.Fatalf("Expected empty string, got '%s'\\n", string(b))
|
|
}}
|
|
|
|
unmarshalHelper(t, "{lastValueUpper}", &e, &overwritten)
|
|
|
|
err = xml.Unmarshal([]byte("<GARBAGE><!LALDK>"), &overwritten)
|
|
if err == nil {{
|
|
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))
|
|
}}
|
|
}}
|
|
"""
|
|
|
|
with open("constants_test.go", 'w') as f:
|
|
f.write(test_header)
|
|
|
|
for enum in enums:
|
|
enumLower = enum[:1].lower() + enum[1:].replace(" ", "")
|
|
firstValueUpper = enums[enum][0][0].upper()
|
|
lastValueUpper = enums[enum][0][-1].upper()
|
|
f.write(test_template.format(enum=enum,
|
|
enumLower=enumLower,
|
|
firstValueUpper=firstValueUpper,
|
|
lastValueUpper=lastValueUpper))
|