diff --git a/accounts.go b/accounts.go index c71073a..9c35250 100644 --- a/accounts.go +++ b/accounts.go @@ -39,6 +39,7 @@ func GetAccounts() (*models.AccountsResponse, error) { func GetAccount(accountId string) (*models.Account, error) { apiUrl := fmt.Sprintf("%s/accounts/%s?include=contacts", _apiPrefix, accountId) + color.Green("GetAccount:%v", apiUrl) req, err := http.NewRequest("GET", apiUrl, nil) req.Header.Add("Authorization", _jwt) @@ -78,7 +79,7 @@ func GetCashTotals(accountId string) (*models.CashTotal, error) { return nil, errors.New(res.Status) } body, _ := ioutil.ReadAll(res.Body) - color.Red("GetCashTotals:body:%v", string(body)) + //color.Red("GetCashTotals:body:%v", string(body)) response := models.CashTotal{} if err := json.Unmarshal(body, &response); err != nil { diff --git a/cash-transactions.go b/cash-transactions.go index e00f91c..bd626fe 100644 --- a/cash-transactions.go +++ b/cash-transactions.go @@ -1,17 +1,25 @@ package primetrust import ( + "bytes" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" + "net/url" + "strconv" + "strings" + "time" "github.com/cloudmode/go-primetrust/models" + "github.com/fatih/color" + "github.com/tidwall/gjson" ) -func GetCashTransactions() (*models.CashTransactionsResponse, error) { - apiUrl := fmt.Sprintf("%s/cash-transactions", _apiPrefix) +func GetCashTransaction(transactionID string) (*models.CashTransaction, error) { + apiUrl := fmt.Sprintf("%s/cash-transactions/%s", _apiPrefix, transactionID) + color.Green("GetCashTransactions:%v", apiUrl) req, err := http.NewRequest("GET", apiUrl, nil) req.Header.Add("Authorization", _jwt) @@ -27,10 +35,132 @@ func GetCashTransactions() (*models.CashTransactionsResponse, error) { } body, _ := ioutil.ReadAll(res.Body) - response := models.CashTransactionsResponse{} + response := models.CashTransaction{} if err := json.Unmarshal(body, &response); err != nil { + color.Red("body:%v", string(body)) return nil, errors.New("unmarshal error") } return &response, nil } + +func GetCashTransactions(accountID string, from, to time.Time) (*models.CashTransactionsResponse, error) { + filter := fmt.Sprintf("filter[created-at gte]=%s&filter[created-at lte]=%s", + from.Format(time.RFC3339), to.Format(time.RFC3339)) + color.Blue("filter:%s", filter) + apiUrl := fmt.Sprintf("%s/cash-transactions?%s&page[number]=1&page[size]=100&include=account-cash-transfer-from,account-cash-transfer-to&sort=-created-at&account.id=%s", + _apiPrefix, url.PathEscape(filter), accountID) + + //apiUrl = url.QueryEscape(apiUrl) + + req, err := http.NewRequest("GET", apiUrl, nil) + req.Header.Add("Authorization", _jwt) + + client := &http.Client{} + res, err := client.Do(req) + if err != nil { + color.Red("error getting accountID:%s:%s", filter) + return nil, err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + color.Red("wetf:%v", res.Status) + return nil, errors.New(res.Status) + } + body, _ := ioutil.ReadAll(res.Body) + //color.Red("body:%s", body) + + transactions := models.CashTransactionsResponse{} + if err := json.Unmarshal(body, &transactions); err != nil { + return nil, errors.New("unmarshal error") + } + + return &transactions, nil +} + +// NewFundsTransfer ... +func NewFundsTransfer(from, to, reference string, amount float64) *models.FundTransfer { + attrs := models.FundTransferAttributes{FromAccountID: from, ToAccountID: to, Amount: amount, Reference: reference, CurrencyType: "USD"} + data := models.FundTransferData{Type: "account-cash-transfers", Attributes: attrs} + ft := models.FundTransfer{Data: data} + return &ft +} + +// FundsTransfer ... +// trying a JSON parsing trick from https://stackoverflow.com/questions/35583735/unmarshaling-into-an-interface-and-then-performing-type-assertion +// because Included is an array of CashTransfer and CashTransaction +func FundsTransfer(from, to, amount, reference string) (*models.CashTransfer, error) { + tAmount, err := strconv.ParseFloat(amount, 64) + if err != nil { + return nil, err + } + ft := NewFundsTransfer(from, to, reference, tAmount) + jsonData := new(bytes.Buffer) + json.NewEncoder(jsonData).Encode(ft) + + apiURL := fmt.Sprintf("%s/account-cash-transfers?include=to-account-cash-totals,from-account-cash-totals,to-cash-transaction,from-cash-transaction", _apiPrefix) + //color.Green("FundsTransfer:%v", apiUrl) + + req, err := http.NewRequest("POST", apiURL, jsonData) + req.Header.Set("Content-Type", "application/json") + req.Header.Add("Authorization", _jwt) + + client := &http.Client{} + res, err := client.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + body, _ := ioutil.ReadAll(res.Body) + + if res.StatusCode != http.StatusCreated { + return nil, fmt.Errorf("%s: %s", res.Status, string(body)) + } + + response := models.CashTransfer{} + + if err := json.Unmarshal(body, &response); err != nil { + color.Black("FundsTransfer unmarshal error %v", string(body)) + return nil, err + } + + included := gjson.ParseBytes(body).Get("included") + for _, raw := range included.Array() { + t := raw.Get("type") + r := raw.Get("relationships.account.links.related") + if strings.Contains(r.String(), from) { + if t.String() == "account-cash-totals" { + if err := json.Unmarshal([]byte(raw.Raw), &response.FromCashData); err != nil { + color.Red("shit:%v", err) + } + color.Green("CashTotal:%v", PrettyPrint(response.FromCashData)) + } else if t.String() == "cash-transactions" { + if err := json.Unmarshal([]byte(raw.Raw), &response.FromCashTransaction); err != nil { + color.Red("shit:%v", err) + } + } + } else if strings.Contains(r.String(), to) { + if t.String() == "account-cash-totals" { + if err := json.Unmarshal([]byte(raw.Raw), &response.ToCashData); err != nil { + color.Red("shit:%v", err) + } + } else if t.String() == "cash-transactions" { + if err := json.Unmarshal([]byte(raw.Raw), &response.ToCashTransaction); err != nil { + color.Red("shit:%v", err) + } + } + } + + } + color.Red("FundsTransfer:response:%+v", PrettyPrint(response)) + + return &response, nil +} + +// PrettyPrint ... +func PrettyPrint(thing interface{}) string { + s, _ := json.MarshalIndent(thing, "", "\t") + return string(s) +} diff --git a/go.mod b/go.mod index 486d276..dcf8087 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 + github.com/tidwall/gjson v1.6.0 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 ) diff --git a/go.sum b/go.sum index 1334d09..faa6105 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,12 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= diff --git a/models/cash-transactions.go b/models/cash-transactions.go index 343d454..746c425 100644 --- a/models/cash-transactions.go +++ b/models/cash-transactions.go @@ -5,20 +5,17 @@ import ( ) type CashTransactionAttributes struct { - ID string `json:"id,omitempty"` - ActualSettlementDate string `json:"actual-settlement-date"` - Amount float64 `json:"amount"` - CommentsLine1 string `json:"comments-line-1" bson:"comments-line-1"` - CommentsLine2 string `json:"comments-line-2" bson:"comments-line-2"` - CommentsLine3 string `json:"comments-line-3" bson:"comments-line-3"` - CommentsLine4 string `json:"comments-line-4" bson:"comments-line-4"` - CreatedAt time.Time `json:"actual-settlement-date" bson:"actual-settlement-date"` - Currency string `json:"currency"` - CustomerReference string `json:"customer-reference" bson:"customer-reference"` - EffectiveSettlementDate string `json:"effective-settlement-date" bson:"effective-settlement-date"` - SettlementDate string `json:"settlement-date"` - TradeDate string `json:"trade-date" bson:"trade-date"` - TransactionNumber int `json:"transaction-number" bson:"transaction-number"` + ID string `json:"id,omitempty"` + Amount float64 `json:"amount"` + Comments1 string `json:"comments-1" bson:"comments-1"` + Comments2 string `json:"comments-2" bson:"comments-2"` + Comments3 string `json:"comments-3" bson:"comments-3"` + Comments4 string `json:"comments-4" bson:"comments-4"` + CreatedAt time.Time `json:"created-at" bson:"created-at"` + CurrencyType string `json:"currency-type"` + CustomerReference string `json:"customer-reference" bson:"customer-reference"` + EffectiveAt time.Time `json:"effective-at" bson:"effective-at"` + SettledOn string `json:"settled-on"` } type CashTransactionData struct { @@ -27,6 +24,16 @@ type CashTransactionData struct { Attributes CashTransactionAttributes `json:"attributes"` Links Links `json:"links"` Relationships Relationships `json:"relationships"` + Included interface{} `json:"included"` +} + +type CashTransactionDataNoExtra struct { + ID string `json:"id,omitempty"` + Type string `json:"type"` + Attributes CashTransactionAttributes `json:"attributes"` + //Links Links `json:"links"` + //Relationships Relationships `json:"relationships"` + //Included interface{} `json:"included"` } type CashTransaction struct { @@ -35,5 +42,23 @@ type CashTransaction struct { type CashTransactionsResponse struct { CollectionResponse - Data []CashTransaction `json:"data"` + Data []CashTransactionDataNoExtra `json:"data"` + Included []CashTransferDataNoExtra `json:"included"` +} + +type FundTransfer struct { + Data FundTransferData `json:"data"` +} + +type FundTransferData struct { + Type string `json:"type"` + Attributes FundTransferAttributes `json:"attributes"` +} + +type FundTransferAttributes struct { + FromAccountID string `json:"from-account-id,omitempty"` + ToAccountID string `json:"to-account-id,omitempty"` + Amount float64 `json:"amount"` + CurrencyType string `json:"currency-type"` + Reference string `json:"reference"` } diff --git a/models/cash-transfer.go b/models/cash-transfer.go new file mode 100644 index 0000000..72122ff --- /dev/null +++ b/models/cash-transfer.go @@ -0,0 +1,47 @@ +package models + +import ( + "encoding/json" + "time" +) + +type TypedJson struct { + Type string + Data json.RawMessage +} + +type CashTransferAttributes struct { + Amount float64 `json:"amount"` + CreatedAt time.Time `json:"created-at"` + UpdatedAt time.Time `json:"updated-at"` + CurrencyType string `json:"currency-type,omitempty"` + Reference string `json:"reference,omitempty"` + Status string `json:"status,omitempty"` + ReversalDetails string `json:"reversal-details,omitempty"` + Included []interface{} `json:"included"` +} + +type CashTransferData struct { + ID string `json:"id,omitempty"` + Type string `json:"type"` + Attributes CashTransferAttributes `json:"attributes"` + Links Links `json:"links"` + Relationships Relationships `json:"relationships"` +} + +type CashTransfer struct { + Data CashTransferData `json:"data"` + Included []TypedJson `json:"included"` + FromCashData CashData + ToCashData CashData + FromCashTransaction CashTransactionData + ToCashTransaction CashTransactionData +} + +type CashTransferDataNoExtra struct { + ID string `json:"id,omitempty"` + Type string `json:"type"` + Attributes CashTransferAttributes `json:"attributes"` + //Links Links `json:"links"` + //Relationships Relationships `json:"relationships"` +} diff --git a/models/relationships.go b/models/relationships.go index 9ee873a..3db6247 100644 --- a/models/relationships.go +++ b/models/relationships.go @@ -55,5 +55,7 @@ type Relationships struct { OwnersAndGrantors Relationship `json:"owners-and-grantors,omitempty"` FundsTransfers Relationship `json:"funds-transfers,omitempty"` Organization Relationship `json:"organization,omitempty"` + FromCashTransaction Relationship2 `json:"from-cash-transaction,omitempty"` + ToCashTransaction Relationship2 `json:"to-cash-transaction,omitempty"` WebhookConfig Relationship2 `json:"webhook-config,omitempty"` }