package ofxgo import ( "fmt" "github.com/aclindsa/xml" ) // AcctInfoRequest represents a request for the server to provide information // for all of the user's available accounts at this FI type AcctInfoRequest struct { XMLName xml.Name `xml:"ACCTINFOTRNRQ"` TrnUID UID `xml:"TRNUID"` CltCookie String `xml:"CLTCOOKIE,omitempty"` TAN String `xml:"TAN,omitempty"` // Transaction authorization number // TODO `xml:"OFXEXTENSION,omitempty"` DtAcctUp Date `xml:"ACCTINFORQ>DTACCTUP"` } // Name returns the name of the top-level transaction XML/SGML element func (r *AcctInfoRequest) Name() string { return "ACCTINFOTRNRQ" } // Valid returns (true, nil) if this struct would be valid OFX if marshalled // into XML/SGML func (r *AcctInfoRequest) Valid(version ofxVersion) (bool, error) { if ok, err := r.TrnUID.Valid(); !ok { return false, err } // TODO implement return true, nil } // Type returns which message set this message belongs to (which Request // element of type []Message it should appended to) func (r *AcctInfoRequest) Type() messageType { return SignupRq } // HolderInfo contains the information a FI has about an account-holder type HolderInfo struct { XMLName xml.Name FirstName String `xml:"FIRSTNAME"` MiddleName String `xml:"MIDDLENAME,omitempty"` LastName String `xml:"LASTNAME"` Addr1 String `xml:"ADDR1"` Addr2 String `xml:"ADDR2,omitempty"` Addr3 String `xml:"ADDR3,omitempty"` City String `xml:"CITY"` State String `xml:"STATE"` PostalCode String `xml:"POSTALCODE"` Country String `xml:"COUNTRY,omitempty"` DayPhone String `xml:"DAYPHONE,omitempty"` EvePhone String `xml:"EVEPHONE,omitempty"` Email String `xml:"EMAIL,omitempty"` HolderType holderType `xml:"HOLDERTYPE,omitempty"` // One of INDIVIDUAL, JOINT, CUSTODIAL, TRUST, OTHER } // BankAcctInfo contains information about a bank account, including how to // access it (BankAcct), and whether it supports downloading transactions // (SupTxDl). type BankAcctInfo struct { XMLName xml.Name `xml:"BANKACCTINFO"` BankAcctFrom BankAcct `xml:"BANKACCTFROM"` SupTxDl Boolean `xml:"SUPTXDL"` // Supports downloading transactions (as opposed to balance only) XferSrc Boolean `xml:"XFERSRC"` // Enabled as source for intra/interbank transfer XferDest Boolean `xml:"XFERDEST"` // Enabled as destination for intra/interbank transfer MaturityDate Date `xml:"MATURITYDATE,omitempty"` // Maturity date for CD, if CD MaturityAmt Amount `xml:"MATURITYAMOUNT,omitempty"` // Maturity amount for CD, if CD MinBalReq Amount `xml:"MINBALREQ,omitempty"` // Minimum balance required to avoid service fees AcctClassification acctClassification `xml:"ACCTCLASSIFICATION,omitempty"` // One of PERSONAL, BUSINESS, CORPORATE, OTHER OverdraftLimit Amount `xml:"OVERDRAFTLIMIT,omitempty"` SvcStatus svcStatus `xml:"SVCSTATUS"` // One of AVAIL (available, but not yet requested), PEND (requested, but not yet available), ACTIVE } // String makes pointers to BankAcctInfo structs print nicely func (bai *BankAcctInfo) String() string { return fmt.Sprintf("%+v", *bai) } // CCAcctInfo contains information about a credit card account, including how // to access it (CCAcct), and whether it supports downloading transactions // (SupTxDl). type CCAcctInfo struct { XMLName xml.Name `xml:"CCACCTINFO"` CCAcctFrom CCAcct `xml:"CCACCTFROM"` SupTxDl Boolean `xml:"SUPTXDL"` // Supports downloading transactions (as opposed to balance only) XferSrc Boolean `xml:"XFERSRC"` // Enabled as source for intra/interbank transfer XferDest Boolean `xml:"XFERDEST"` // Enabled as destination for intra/interbank transfer AcctClassification acctClassification `xml:"ACCTCLASSIFICATION,omitempty"` // One of PERSONAL, BUSINESS, CORPORATE, OTHER SvcStatus svcStatus `xml:"SVCSTATUS"` // One of AVAIL (available, but not yet requested), PEND (requested, but not yet available), ACTIVE } // String makes pointers to CCAcctInfo structs print nicely func (ci *CCAcctInfo) String() string { return fmt.Sprintf("%+v", *ci) } // InvAcctInfo contains information about an investment account, including how // to access it (InvAcct), and whether it supports downloading transactions // (SupTxDl). type InvAcctInfo struct { XMLName xml.Name `xml:"INVACCTINFO"` InvAcctFrom InvAcct `xml:"INVACCTFROM"` UsProductType usProductType `xml:"USPRODUCTTYPE"` // One of 401K, 403B, IRA, KEOGH, OTHER, SARSEP, SIMPLE, NORMAL, TDA, TRUST, UGMA Checking Boolean `xml:"CHECKING"` // Has check-writing privileges SvcStatus svcStatus `xml:"SVCSTATUS"` // One of AVAIL (available, but not yet requested), PEND (requested, but not yet available), ACTIVE InvAcctType holderType `xml:"INVACCTTYPE,omitempty"` // One of INDIVIDUAL, JOINT, TRUST, CORPORATE OptionLevel String `xml:"OPTIONLEVEL,omitempty"` // Text desribing option trading privileges } // String makes pointers to InvAcctInfo structs print nicely func (iai *InvAcctInfo) String() string { return fmt.Sprintf("%+v", *iai) } // AcctInfo represents generic account information. It should contain one (and // only one) *AcctInfo element corresponding to the tyep of account it // represents. type AcctInfo struct { XMLName xml.Name `xml:"ACCTINFO"` Name String `xml:"NAME,omitempty"` Desc String `xml:"DESC,omitempty"` Phone String `xml:"PHONE,omitempty"` PrimaryHolder HolderInfo `xml:"HOLDERINFO>PRIMARYHOLDER,omitempty"` SecondaryHolder HolderInfo `xml:"HOLDERINFO>SECONDARYHOLDER,omitempty"` // Only one of the rest of the fields will be valid for any given AcctInfo BankAcctInfo *BankAcctInfo `xml:"BANKACCTINFO,omitempty"` CCAcctInfo *CCAcctInfo `xml:"CCACCTINFO,omitempty"` InvAcctInfo *InvAcctInfo `xml:"INVACCTINFO,omitempty"` // TODO LOANACCTINFO // TODO BPACCTINFO? } // AcctInfoResponse contains the information about all a user's accounts // accessible from this FI type AcctInfoResponse struct { XMLName xml.Name `xml:"ACCTINFOTRNRS"` TrnUID UID `xml:"TRNUID"` Status Status `xml:"STATUS"` CltCookie String `xml:"CLTCOOKIE,omitempty"` // TODO `xml:"OFXEXTENSION,omitempty"` DtAcctUp Date `xml:"ACCTINFORS>DTACCTUP"` AcctInfo []AcctInfo `xml:"ACCTINFORS>ACCTINFO,omitempty"` } // Name returns the name of the top-level transaction XML/SGML element func (air *AcctInfoResponse) Name() string { return "ACCTINFOTRNRS" } // Valid returns (true, nil) if this struct was valid OFX when unmarshalled func (air *AcctInfoResponse) Valid(version ofxVersion) (bool, error) { if ok, err := air.TrnUID.Valid(); !ok { return false, err } //TODO implement return true, nil } // Type returns which message set this message belongs to (which Response // element of type []Message it belongs to) func (air *AcctInfoResponse) Type() messageType { return SignupRs }