diff --git a/invstmt_test.go b/invstmt_test.go new file mode 100644 index 0000000..0a97a32 --- /dev/null +++ b/invstmt_test.go @@ -0,0 +1,559 @@ +package ofxgo_test + +import ( + "github.com/aclindsa/ofxgo" + "math/big" + "strings" + "testing" + "time" +) + +func TestMarshalInvStatementRequest(t *testing.T) { + var expectedString string = ` + + + + + 20160224131905.000[-5:EST] + 1998124 + Sup3eSekrit + ENG + + First Bank + 01 + + MYAPP + 1234 + + + + + 382827d6-e2d0-4396-bf3b-665979285420 + + + fi.example.com + 82736664 + + + 20160101000000.000[-5:EST] + Y + + Y + + Y + + Y + + + +` + + var client = ofxgo.Client{ + AppId: "MYAPP", + AppVer: "1234", + SpecVersion: "203", + } + + var request ofxgo.Request + request.Signon.UserId = "1998124" + request.Signon.UserPass = "Sup3eSekrit" + request.Signon.Org = "First Bank" + request.Signon.Fid = "01" + + EST := time.FixedZone("EST", -5*60*60) + dtstart := ofxgo.Date(time.Date(2016, 1, 1, 0, 0, 0, 0, EST)) + + statementRequest := ofxgo.InvStatementRequest{ + TrnUID: "382827d6-e2d0-4396-bf3b-665979285420", + InvAcctFrom: ofxgo.InvAcct{ + BrokerId: "fi.example.com", + AcctId: "82736664", + }, + DtStart: &dtstart, + Include: true, + IncludeOO: true, + IncludePos: true, + IncludeBalance: true, + } + request.InvStmt = append(request.InvStmt, &statementRequest) + + request.SetClientFields(&client) + // Overwrite the DtClient value set by SetClientFields to time.Now() + request.Signon.DtClient = ofxgo.Date(time.Date(2016, 2, 24, 13, 19, 5, 0, EST)) + + marshalCheckRequest(t, &request, expectedString) +} + +func TestUnmarshalInvStatementResponse(t *testing.T) { + responseReader := strings.NewReader(` + + + + + + 0 + INFO + + 20170401201244 + ENG + + INVSTRUS + 9999 + + + + + + 1a0117ad-692b-4c6a-a21b-020d37d34d49 + + 0 + INFO + + + 20170331000000 + USD + + invstrus.com + 91827364 + + + 20170101000000 + 20170331000000 + + + + 729483191 + 20170203 + 20170207 + + + 78462F103 + CUSIP + + 100 + 229.00 + 9.00 + -22909.00 + CASH + CASH + + BUY + + + + CREDIT + 20170120 + 20170118 + 20170123 + 22000.00 + 993838 + DEPOSIT + CHECK 19980 + + CASH + + + + + + + 78462F103 + CUSIP + + CASH + LONG + 200 + 235.74 + 47148.00 + 20170331160000 + Price as of previous close + + + + + + 129887339 + CUSIP + + CASH + LONG + 1 + 3 + 300 + 20170331160000 + + + + + 16.73 + -819.20 + 0 + + + Sweep Int Rate + Current interest rate for sweep account balances + PERCENT + 0.25 + 20170401 + + + + + + + 76464632 + + 922908645 + CUSIP + + 20170310124445 + 10 + CASH + GOODTILCANCEL + NONE + 168.50 + + BUY + SHARES + + + + 999387423 + + 899422348 + CUSIP + + 20170324031900 + 25 + CASH + GOODTILCANCEL + ALLORNONE + 19.75 + + BUY + + + + + + + + + + + 78462F103 + CUSIP + + S&P 500 ETF + SPY + 99184 + + 1.92 + OTHER + + + + + 129887339 + CUSIP + + John's Fertilizer Puts + FERTP + 882919 + + PUT + 79.00 + 20170901 + 100 + + 983322180 + CUSIP + + LARGESTOCK + + + + + 899422348 + CUSIP + + Whatchamacallit, Inc. + WHAT + 883897 + + 17 + SMALLSTOCK + + + + + 922908645 + CUSIP + + Mid-Cap Index Fund Admiral Shares + VIMAX + + + + +`) + var expected ofxgo.Response + GMT := time.FixedZone("GMT", 0) + + expected.Version = "203" + expected.Signon.Status.Code = 0 + expected.Signon.Status.Severity = "INFO" + expected.Signon.DtServer = ofxgo.Date(time.Date(2017, 4, 1, 20, 12, 44, 0, GMT)) + expected.Signon.Language = "ENG" + expected.Signon.Org = "INVSTRUS" + expected.Signon.Fid = "9999" + + var units1, unitprice1, commission1, total1, amount2 big.Rat + units1.SetFrac64(100, 1) + unitprice1.SetFrac64(229, 1) + commission1.SetFrac64(9, 1) + total1.SetFrac64(-22909, 1) + amount2.SetFrac64(22000, 1) + + dtuser := ofxgo.Date(time.Date(2017, 1, 18, 0, 0, 0, 0, GMT)) + dtavail := ofxgo.Date(time.Date(2017, 1, 23, 0, 0, 0, 0, GMT)) + dtsettle := ofxgo.Date(time.Date(2017, 2, 7, 0, 0, 0, 0, GMT)) + + invtranlist := ofxgo.InvTranList{ + DtStart: ofxgo.Date(time.Date(2017, 1, 1, 0, 0, 0, 0, GMT)), + DtEnd: ofxgo.Date(time.Date(2017, 3, 31, 0, 0, 0, 0, GMT)), + InvTransactions: []ofxgo.InvTransaction{ + ofxgo.BuyStock{ + InvBuy: ofxgo.InvBuy{ + InvTran: ofxgo.InvTran{ + FiTId: "729483191", + DtTrade: ofxgo.Date(time.Date(2017, 2, 3, 0, 0, 0, 0, GMT)), + DtSettle: &dtsettle, + }, + SecId: ofxgo.SecurityId{ + UniqueId: "78462F103", + UniqueIdType: "CUSIP", + }, + Units: ofxgo.Amount(units1), + UnitPrice: ofxgo.Amount(unitprice1), + Commission: ofxgo.Amount(commission1), + Total: ofxgo.Amount(total1), + SubAcctSec: "CASH", + SubAcctFund: "CASH", + }, + BuyType: "BUY", + }, + }, + BankTransactions: []ofxgo.InvBankTransaction{ + ofxgo.InvBankTransaction{ + Transactions: []ofxgo.Transaction{ + ofxgo.Transaction{ + TrnType: "CREDIT", + DtPosted: ofxgo.Date(time.Date(2017, 1, 20, 0, 0, 0, 0, GMT)), + DtUser: &dtuser, + DtAvail: &dtavail, + TrnAmt: ofxgo.Amount(amount2), + FiTId: "993838", + Name: "DEPOSIT", + Memo: "CHECK 19980", + }, + }, + SubAcctFund: "CASH", + }, + }, + } + + var availcash, marginbalance, shortbalance, balvalue big.Rat + availcash.SetFrac64(1673, 100) + marginbalance.SetFrac64(-8192, 10) + shortbalance.SetFrac64(0, 1) + balvalue.SetFrac64(25, 100) + + baldtasof := ofxgo.Date(time.Date(2017, 4, 1, 0, 0, 0, 0, GMT)) + + invbalance := ofxgo.InvBalance{ + AvailCash: ofxgo.Amount(availcash), + MarginBalance: ofxgo.Amount(marginbalance), + ShortBalance: ofxgo.Amount(shortbalance), + BalList: []ofxgo.Balance{ + ofxgo.Balance{ + Name: "Sweep Int Rate", + Desc: "Current interest rate for sweep account balances", + BalType: "PERCENT", + Value: ofxgo.Amount(balvalue), + DtAsOf: &baldtasof, + }, + }, + } + + var balamt, availbalamt, posunits1, posunitprice1, posmktval1, posunits2, posunitprice2, posmktval2, oounits1, oolimitprice1, oounits2, oolimitprice2 big.Rat + balamt.SetFrac64(20029, 100) + availbalamt.SetFrac64(20029, 100) + posunits1.SetFrac64(200, 1) + posunitprice1.SetFrac64(23574, 100) + posmktval1.SetFrac64(47148, 1) + posunits2.SetFrac64(1, 1) + posunitprice2.SetFrac64(3, 1) + posmktval2.SetFrac64(300, 1) + oounits1.SetFrac64(10, 1) + oolimitprice1.SetFrac64(16850, 100) + oounits2.SetFrac64(25, 1) + oolimitprice2.SetFrac64(1975, 100) + + statementResponse := ofxgo.InvStatementResponse{ + TrnUID: "1a0117ad-692b-4c6a-a21b-020d37d34d49", + Status: ofxgo.Status{ + Code: 0, + Severity: "INFO", + }, + DtAsOf: ofxgo.Date(time.Date(2017, 3, 31, 0, 0, 0, 0, GMT)), + CurDef: "USD", + InvAcctFrom: ofxgo.InvAcct{ + BrokerId: "invstrus.com", + AcctId: "91827364", + }, + InvTranList: &invtranlist, + InvPosList: ofxgo.PositionList{ + ofxgo.StockPosition{ + InvPos: ofxgo.InvPosition{ + SecId: ofxgo.SecurityId{ + UniqueId: "78462F103", + UniqueIdType: "CUSIP", + }, + HeldInAcct: "CASH", + PosType: "LONG", + Units: ofxgo.Amount(posunits1), + UnitPrice: ofxgo.Amount(posunitprice1), + MktVal: ofxgo.Amount(posmktval1), + DtPriceAsOf: ofxgo.Date(time.Date(2017, 3, 31, 16, 0, 0, 0, GMT)), + Memo: "Price as of previous close", + }, + }, + ofxgo.OptPosition{ + InvPos: ofxgo.InvPosition{ + SecId: ofxgo.SecurityId{ + UniqueId: "129887339", + UniqueIdType: "CUSIP", + }, + HeldInAcct: "CASH", + PosType: "LONG", + Units: ofxgo.Amount(posunits2), + UnitPrice: ofxgo.Amount(posunitprice2), + MktVal: ofxgo.Amount(posmktval2), + DtPriceAsOf: ofxgo.Date(time.Date(2017, 3, 31, 16, 0, 0, 0, GMT)), + }, + }, + }, + InvBal: &invbalance, + InvOOList: ofxgo.OOList{ + ofxgo.OOBuyMF{ + OO: ofxgo.OO{ + FiTId: "76464632", + SecId: ofxgo.SecurityId{ + UniqueId: "922908645", + UniqueIdType: "CUSIP", + }, + DtPlaced: ofxgo.Date(time.Date(2017, 3, 10, 12, 44, 45, 0, GMT)), + Units: ofxgo.Amount(oounits1), + SubAcct: "CASH", + Duration: "GOODTILCANCEL", + Restriction: "NONE", + LimitPrice: ofxgo.Amount(oolimitprice1), + }, + BuyType: "BUY", + UnitType: "SHARES", + }, + ofxgo.OOBuyStock{ + OO: ofxgo.OO{ + FiTId: "999387423", + SecId: ofxgo.SecurityId{ + UniqueId: "899422348", + UniqueIdType: "CUSIP", + }, + DtPlaced: ofxgo.Date(time.Date(2017, 3, 24, 3, 19, 0, 0, GMT)), + Units: ofxgo.Amount(oounits2), + SubAcct: "CASH", + Duration: "GOODTILCANCEL", + Restriction: "ALLORNONE", + LimitPrice: ofxgo.Amount(oolimitprice2), + }, + BuyType: "BUY", + }, + }, + } + expected.InvStmt = append(expected.InvStmt, &statementResponse) + + var yield1, yield2, strikeprice big.Rat + yield1.SetFrac64(192, 100) + yield2.SetFrac64(17, 1) + strikeprice.SetFrac64(79, 1) + + seclist := ofxgo.SecurityList{ + Securities: []ofxgo.Security{ + ofxgo.StockInfo{ + SecInfo: ofxgo.SecInfo{ + SecId: ofxgo.SecurityId{ + UniqueId: "78462F103", + UniqueIdType: "CUSIP", + }, + SecName: "S&P 500 ETF", + Ticker: "SPY", + FiId: "99184", + }, + Yield: ofxgo.Amount(yield1), + AssetClass: "OTHER", + }, + ofxgo.OptInfo{ + SecInfo: ofxgo.SecInfo{ + SecId: ofxgo.SecurityId{ + UniqueId: "129887339", + UniqueIdType: "CUSIP", + }, + SecName: "John's Fertilizer Puts", + Ticker: "FERTP", + FiId: "882919", + }, + OptType: "PUT", + StrikePrice: ofxgo.Amount(strikeprice), + DtExpire: ofxgo.Date(time.Date(2017, 9, 1, 0, 0, 0, 0, GMT)), + ShPerCtrct: 100, + SecId: &ofxgo.SecurityId{ + UniqueId: "983322180", + UniqueIdType: "CUSIP", + }, + AssetClass: "LARGESTOCK", + }, + ofxgo.StockInfo{ + SecInfo: ofxgo.SecInfo{ + SecId: ofxgo.SecurityId{ + UniqueId: "899422348", + UniqueIdType: "CUSIP", + }, + SecName: "Whatchamacallit, Inc.", + Ticker: "WHAT", + FiId: "883897", + }, + Yield: ofxgo.Amount(yield2), + AssetClass: "SMALLSTOCK", + }, + ofxgo.MFInfo{ + SecInfo: ofxgo.SecInfo{ + SecId: ofxgo.SecurityId{ + UniqueId: "922908645", + UniqueIdType: "CUSIP", + }, + SecName: "Mid-Cap Index Fund Admiral Shares", + Ticker: "VIMAX", + }, + }, + }, + } + expected.SecList = append(expected.SecList, &seclist) + + response, err := ofxgo.ParseResponse(responseReader) + if err != nil { + t.Fatalf("Unexpected error unmarshalling response: %s\n", err) + } + + checkResponsesEqual(t, &expected, response) +}