diff --git a/banking.go b/banking.go index 49ab8e4..fa9f453 100644 --- a/banking.go +++ b/banking.go @@ -28,6 +28,10 @@ func (r *StatementRequest) Valid() (bool, error) { return true, nil } +func (r *StatementRequest) Type() messageType { + return BankRq +} + type Payee struct { XMLName xml.Name `xml:"PAYEE"` Name String `xml:"NAME"` @@ -155,6 +159,10 @@ func (sr StatementResponse) Valid() (bool, error) { return true, nil } +func (sr StatementResponse) Type() messageType { + return BankRs +} + func decodeBankingMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) { var msgs []Message for { diff --git a/common.go b/common.go index 7b93b39..329a93a 100644 --- a/common.go +++ b/common.go @@ -5,11 +5,115 @@ import ( "github.com/aclindsa/go/src/encoding/xml" ) -// Represents a top-level OFX message set (i.e. BANKMSGSRSV1) +// Represents an OFX message in a message set type Message interface { - Name() string // The name of the OFX element this set represents + Name() string // The name of the OFX transaction wrapper element this represents Valid() (bool, error) // Called before a Message is marshaled and after // it's unmarshaled to ensure the request or response is valid + Type() messageType // The message set this message belongs to +} + +type messageType uint + +const ( + // Requests + SignonRq messageType = iota + SignupRq + BankRq + CreditCardRq + LoanRq + InvStmtRq + InterXferRq + WireXferRq + BillpayRq + EmailRq + SecListRq + PresDirRq + PresDlvRq + ProfileRq + ImageRq + // Responses + SignonRs + SignupRs + BankRs + CreditCardRs + LoanRs + InvStmtRs + InterXferRs + WireXferRs + BillpayRs + EmailRs + SecListRs + PresDirRs + PresDlvRs + ProfileRs + ImageRs +) + +func (t messageType) String() string { + switch t { + case SignonRq: + return "SIGNONMSGSRQV1" + case SignupRq: + return "SIGNUPMSGSRQV1" + case BankRq: + return "BANKMSGSRQV1" + case CreditCardRq: + return "CREDITCARDMSGSRQV1" + case LoanRq: + return "LOANMSGSRQV1" + case InvStmtRq: + return "INVSTMTMSGSRQV1" + case InterXferRq: + return "INTERXFERMSGSRQV1" + case WireXferRq: + return "WIREXFERMSGSRQV1" + case BillpayRq: + return "BILLPAYMSGSRQV1" + case EmailRq: + return "EMAILMSGSRQV1" + case SecListRq: + return "SECLISTMSGSRQV1" + case PresDirRq: + return "PRESDIRMSGSRQV1" + case PresDlvRq: + return "PRESDLVMSGSRQV1" + case ProfileRq: + return "PROFMSGSRQV1" + case ImageRq: + return "IMAGEMSGSRQV1" + case SignonRs: + return "SIGNONMSGSRSV1" + case SignupRs: + return "SIGNUPMSGSRSV1" + case BankRs: + return "BANKMSGSRSV1" + case CreditCardRs: + return "CREDITCARDMSGSRSV1" + case LoanRs: + return "LOANMSGSRSV1" + case InvStmtRs: + return "INVSTMTMSGSRSV1" + case InterXferRs: + return "INTERXFERMSGSRSV1" + case WireXferRs: + return "WIREXFERMSGSRSV1" + case BillpayRs: + return "BILLPAYMSGSRSV1" + case EmailRs: + return "EMAILMSGSRSV1" + case SecListRs: + return "SECLISTMSGSRSV1" + case PresDirRs: + return "PRESDIRMSGSRSV1" + case PresDlvRs: + return "PRESDLVMSGSRSV1" + case ProfileRs: + return "PROFMSGSRSV1" + case ImageRs: + return "IMAGEMSGSRSV1" + } + panic("Invalid messageType") } // Map of error codes to their meanings, SEVERITY, and conditions under which diff --git a/creditcards.go b/creditcards.go index 77e3f09..fb0cf62 100644 --- a/creditcards.go +++ b/creditcards.go @@ -28,6 +28,10 @@ func (r *CCStatementRequest) Valid() (bool, error) { return true, nil } +func (r *CCStatementRequest) Type() messageType { + return CreditCardRq +} + type CCStatementResponse struct { XMLName xml.Name `xml:"CCSTMTTRNRS"` TrnUID UID `xml:"TRNUID"` @@ -62,6 +66,10 @@ func (sr CCStatementResponse) Valid() (bool, error) { return true, nil } +func (sr CCStatementResponse) Type() messageType { + return CreditCardRs +} + func decodeCCMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) { var msgs []Message for { diff --git a/investments.go b/investments.go index 6f09f6f..ff0ffb3 100644 --- a/investments.go +++ b/investments.go @@ -33,6 +33,10 @@ func (r *InvStatementRequest) Valid() (bool, error) { return true, nil } +func (r *InvStatementRequest) Type() messageType { + return InvStmtRq +} + type InvTran struct { XMLName xml.Name `xml:"INVTRAN"` FiTId String `xml:"FITID"` @@ -816,6 +820,10 @@ func (sr InvStatementResponse) Valid() (bool, error) { return true, nil } +func (sr InvStatementResponse) Type() messageType { + return InvStmtRs +} + func decodeInvestmentsMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) { var msgs []Message for { diff --git a/profile.go b/profile.go index 331fb9f..1a369ca 100644 --- a/profile.go +++ b/profile.go @@ -25,6 +25,10 @@ func (r *ProfileRequest) Valid() (bool, error) { return true, nil } +func (r *ProfileRequest) Type() messageType { + return ProfileRq +} + type SignonInfo struct { XMLName xml.Name `xml:"SIGNONINFO"` SignonRealm String `xml:"SIGNONREALM"` @@ -130,6 +134,10 @@ func (pr ProfileResponse) Valid() (bool, error) { return true, nil } +func (pr ProfileResponse) Type() messageType { + return ProfileRs +} + func decodeProfileMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) { var msgs []Message for { diff --git a/request.go b/request.go index dc6840c..d0a3c35 100644 --- a/request.go +++ b/request.go @@ -29,14 +29,17 @@ type Request struct { indent bool // Whether to indent the marshaled XML } -func marshalMessageSet(e *xml.Encoder, requests []Message, setname string) error { +func marshalMessageSet(e *xml.Encoder, requests []Message, set messageType) error { if len(requests) > 0 { - messageSetElement := xml.StartElement{Name: xml.Name{Local: setname}} + messageSetElement := xml.StartElement{Name: xml.Name{Local: set.String()}} if err := e.EncodeToken(messageSetElement); err != nil { return err } for _, request := range requests { + if request.Type() != set { + return errors.New("Expected " + set.String() + " message , found " + request.Type().String()) + } if ok, err := request.Valid(); !ok { return err } @@ -104,7 +107,7 @@ NEWFILEUID:NONE if ok, err := oq.Signon.Valid(); !ok { return nil, err } - signonMsgSet := xml.StartElement{Name: xml.Name{Local: "SIGNONMSGSRQV1"}} + signonMsgSet := xml.StartElement{Name: xml.Name{Local: SignonRq.String()}} if err := encoder.EncodeToken(signonMsgSet); err != nil { return nil, err } @@ -115,22 +118,22 @@ NEWFILEUID:NONE return nil, err } - if err := marshalMessageSet(encoder, oq.Signup, "SIGNUPMSGSRQV1"); err != nil { + if err := marshalMessageSet(encoder, oq.Signup, SignupRq); err != nil { return nil, err } - if err := marshalMessageSet(encoder, oq.Banking, "BANKMSGSRQV1"); err != nil { + if err := marshalMessageSet(encoder, oq.Banking, BankRq); err != nil { return nil, err } - if err := marshalMessageSet(encoder, oq.CreditCards, "CREDITCARDMSGSRQV1"); err != nil { + if err := marshalMessageSet(encoder, oq.CreditCards, CreditCardRq); err != nil { return nil, err } - if err := marshalMessageSet(encoder, oq.Investments, "INVSTMTMSGSRQV1"); err != nil { + if err := marshalMessageSet(encoder, oq.Investments, InvStmtRq); err != nil { return nil, err } - if err := marshalMessageSet(encoder, oq.Securities, "SECLISTMSGSRQV1"); err != nil { + if err := marshalMessageSet(encoder, oq.Securities, SecListRq); err != nil { return nil, err } - if err := marshalMessageSet(encoder, oq.Profile, "PROFMSGSRQV1"); err != nil { + if err := marshalMessageSet(encoder, oq.Profile, ProfileRq); err != nil { return nil, err } diff --git a/securities.go b/securities.go index 02aa09c..8981de2 100644 --- a/securities.go +++ b/securities.go @@ -37,6 +37,10 @@ func (r *SecListRequest) Valid() (bool, error) { return true, nil } +func (r *SecListRequest) Type() messageType { + return SecListRq +} + type SecListResponse struct { XMLName xml.Name `xml:"SECLISTTRNRS"` TrnUID UID `xml:"TRNUID"` @@ -55,6 +59,10 @@ func (r SecListResponse) Valid() (bool, error) { return true, nil } +func (r SecListResponse) Type() messageType { + return SecListRs +} + type Security interface { SecurityType() string } @@ -176,6 +184,10 @@ func (r SecurityList) Valid() (bool, error) { return true, nil } +func (r SecurityList) Type() messageType { + return SecListRs +} + func (r *SecurityList) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { for { tok, err := nextNonWhitespaceToken(d) diff --git a/signup.go b/signup.go index 0dfa8d6..7daecf9 100644 --- a/signup.go +++ b/signup.go @@ -24,6 +24,10 @@ func (r *AcctInfoRequest) Valid() (bool, error) { return true, nil } +func (r *AcctInfoRequest) Type() messageType { + return SignupRq +} + type HolderInfo struct { XMLName xml.Name FirstName String `xml:"FIRSTNAME"` @@ -125,6 +129,10 @@ func (air AcctInfoResponse) Valid() (bool, error) { return true, nil } +func (air AcctInfoResponse) Type() messageType { + return SignupRs +} + func decodeSignupMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) { var msgs []Message for {