Skip to content
This repository has been archived by the owner on Apr 7, 2022. It is now read-only.

Commit

Permalink
Merge pull request #7 from hellodigit/json-responses
Browse files Browse the repository at this point in the history
v1.0
  • Loading branch information
todoubled committed Aug 4, 2015
2 parents c31df1e + 51930ae commit fb2887b
Show file tree
Hide file tree
Showing 27 changed files with 1,797 additions and 101 deletions.
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# node-intuit

WIP `npm` port of https://github.com/cloocher/aggcat
## Synopsis

### Basic Usage
Inspired by https://github.com/cloocher/aggcat, this is a node module for interacting
with Intuit's Customer Account Data (CAD) API.

## Code Example

```coffeescript
fs = require "fs"
Expand All @@ -17,9 +20,24 @@ config =
certificate: fs.readFileSync path.join(__dirname, "app.crt"), "utf8"
certificatePassword: "password"

intuit = require("intuit")(config)
intuit = require("node-intuit")(config)

intuit.getInstitutionDetails userId, 100000, (err, institutionDetails) ->
console.log institutionDetails
process.exit()
```

## Installation

`npm install --save node-intuit`

## API Reference

See the [tests](https://github.com/hellodigit/node-intuit/blob/master/test/api.coffee)
for all APIs with expected responses.

## Tests

`npm test`

Debug with `DEBUG=node-intuit*`.
84 changes: 70 additions & 14 deletions lib/client.coffee
Original file line number Diff line number Diff line change
@@ -1,37 +1,93 @@
_ = require "lodash"
Request = require "./request"

BASE_URL = "https://financialdatafeed.platform.intuit.com/v1"

zeroBased = (number) ->
("0" + number).slice(-2)

# 2015-07-29
formatDate = (date) ->
year = date.getFullYear()
month = zeroBased date.getMonth() + 1
day = zeroBased date.getDate()
"#{year}-#{month}-#{day}"

module.exports = class IntuitClient
constructor: (@options) ->

request: (method, path, body, done) ->
[body, done] = [{}, body] if typeof(body) is "function"
new Request(@options)[method]("#{BASE_URL}#{path}", body, done)

institutions: (done) ->
@request "get", "/institutions", done
institutions: (userId, done) ->
@options.userId = userId
@request "get", "/institutions", (err, response) ->
return done err if err
done err, response.institution

getInstitutionDetails: (institutionId, done) ->
getInstitutionDetails: (userId, institutionId, done) ->
@options.userId = userId
@request "get", "/institutions/#{institutionId}", done

discoverAndAddAccounts: (institutionId, credentials, done) ->
@request "post", "/institutions/#{institutionId}/logins", credentials, done
discoverAndAddAccounts: (userId, institutionId, credentials, done) ->
@options.userId = userId
@request "post", "/institutions/#{institutionId}/logins", credentials, (err, response) ->
return done err if err
if response.challenge
done err, response
else
done err, response.accounts

handleMfa: (userId, institutionId, challengeSessionId, challengeNodeId, answers, done) ->
@options.headers =
challengeSessionId: challengeSessionId
challengeNodeId: challengeNodeId
@request "post", "/institutions/#{institutionId}/logins", answers, (err, response) ->
return done err if err
done err, response.accounts

getCustomerAccounts: (userId, done) ->
@options.userId = userId
@request "get", "/accounts", (err, response) ->
return done err if err
done err, response.accounts

getAccount: (userId, accountId, done) ->
@options.userId = userId
@request "get", "/accounts/#{accountId}", (err, response) ->
return done err if err
done err, _.first response.accounts

# Download last week of transactions unless a date range is specified
# If no endDate is specified, startDate to current is downloaded
getAccountTransactions: (userId, accountId, startDate, endDate, done) ->
oneWeekAgo = -10080
defaultStartDate = formatDate new Date(new Date().getTime() + oneWeekAgo * 60000)

getCustomerAccounts: (done) ->
@request "get", "/accounts", done
if typeof(startDate) is "function"
[startDate, endDate, done] = [defaultStartDate, null, startDate]
else if typeof(endDate) is "function"
[startDate, endDate, done] = [formatDate(startDate), null, endDate]
else
[startDate, endDate, done] = [formatDate(startDate), formatDate(endDate), done]

getAccount: (accountId, done) ->
@request "get", "/accounts/#{accountId}", done
url = "/accounts/#{accountId}/transactions?txnStartDate=#{startDate}"
url += "&txnEndDate=#{endDate}" if endDate

getAccountTransactions: (accountId, startDate, endDate) ->
@request "get", "/accounts/#{accountId}/transactions", done
@options.userId = userId
@request "get", url, (err, response) ->
return done err if err
done err, response.bankingTransactions

updateInstitutionLogin: (institutionId, loginId, credentials, done) ->
updateInstitutionLogin: (userId, institutionId, loginId, credentials, done) ->
@options.userId = userId
@request "put", "/logins/#{loginId}?refresh=true", credentials, done

deleteAccount: (accountId, done) ->
deleteAccount: (userId, accountId, done) ->
@options.userId = userId
@request "delete", "/accounts/#{accountId}", done

deleteCustomer: ->
deleteCustomer: (userId, done) ->
@options.userId = userId
@request "delete", "/customers", done
4 changes: 3 additions & 1 deletion lib/oauth.coffee
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
debug = require("debug")("node-intuit:oauth")
request = require "request"
Saml = require "./saml"

Expand All @@ -22,7 +23,8 @@ module.exports = class OAuth
"Authorization": "OAuth oauth_consumer_key=\"#{@options.consumerKey}\""
form:
saml_assertion: @saml
request.post params, (err, response, body) =>
request params, (err, response, body) =>
return done err if err
debug "#{params.method} #{response.request.uri.path} - #{response.statusCode} #{response.statusMessage}"
oauth = @parseResponse body
done err, oauth.token, oauth.tokenSecret
37 changes: 27 additions & 10 deletions lib/request.coffee
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
request = require "request"
_ = require "lodash"
debug = require("debug")("node-intuit:request")
OAuth = require "./oauth"
SAML_URL = "https://oauth.intuit.com/oauth/v1/get_access_token_by_saml"

Expand All @@ -9,36 +11,51 @@ module.exports = class Request
_params: (method, url, done) ->
@oauth.getToken (err, token, tokenSecret) =>
return done err if err
optionalHeaders = @options.headers or {}
headers =
"Content-Type": "application/json"
"Accept": "application/json"
params =
method: method
uri: url
headers:
"Content-Type": "application/json"
json: true
oauth:
consumer_key: @options.consumerKey
consumer_secret: @options.consumerSecret
token: token
token_secret: tokenSecret
params.headers = _.merge headers, optionalHeaders
done err, params

request: (params, done) ->
method = if params.method is "DELETE" then params.method.toLowerCase()[0..2] else params.method.toLowerCase()
requestMethod = request[method]
requestMethod params, (err, response, body) ->
return done err if err
debug "#{params.method} #{response.request.uri.path} - #{response.statusCode} #{response.statusMessage}"
return done err, response.statusCode if response.statusCode is 200 and not body
return done err, body unless response.statusCode is 401
{challengenodeid, challengesessionid} = response.headers
done err, {challenge: body.challenge, challengeNodeId: challengenodeid, challengeSessionId: challengesessionid}

get: (url, body, done) ->
@_params "GET", url, (err, params) ->
@_params "GET", url, (err, params) =>
return done err if err
request params, done
@request params, done

post: (url, body, done) ->
@_params "POST", url, (err, params) ->
@_params "POST", url, (err, params) =>
return done err if err
params.body = body
request params, done
@request params, done

put: (url, body, done) ->
@_params "PUT", url, (err, params) ->
@_params "PUT", url, (err, params) =>
return done err if err
params.body = body
request params, done
@request params, done

delete: (url, body, done) ->
@_params "DELETE", url, (err, params) ->
@_params "DELETE", url, (err, params) =>
return done err if err
request params, done
@request params, done
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-intuit",
"version": "0.0.1",
"version": "1.0.0",
"description": "Client for Intuit's Customer Account Data API",
"main": "index.js",
"scripts": {
Expand All @@ -10,13 +10,16 @@
},
"dependencies": {
"coffee-script": "^1.9.3",
"debug": "^2.2.0",
"lodash": "^3.10.0",
"node-uuid": "^1.4.3",
"request": "^2.59.0"
},
"devDependencies": {
"bondjs": "^1.2.3",
"mocha": "^2.2.5",
"nock": "^2.9.1"
"nock": "^2.9.1",
"timekeeper": "0.0.5"
},
"engines": {
"node": "0.12.5",
Expand Down
Loading

0 comments on commit fb2887b

Please sign in to comment.