loco_bill 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +16 -0
- data/init.rb +1 -0
- data/lib/loco_bill/login.rb +5 -0
- data/lib/loco_bill/request.rb +100 -0
- data/lib/loco_bill.rb +13 -0
- metadata +70 -0
data/README
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
An interface for interacting with Bill.com's API. Expects the following constants to be set (in environment.rb or an initializer or what have you):
|
2
|
+
|
3
|
+
BILL_API_APPLICATION_KEY
|
4
|
+
BILL_API_USERNAME
|
5
|
+
BILL_API_PASSWORD
|
6
|
+
BILL_API_ORG_ID
|
7
|
+
|
8
|
+
Requires Nokogiri.
|
9
|
+
|
10
|
+
Use like so:
|
11
|
+
|
12
|
+
login = LocoBill.login
|
13
|
+
login.result.inspect => #<BillApi::RequestResult status="OK", sessionId="xxx", orgID="yyy">
|
14
|
+
|
15
|
+
vendor = BillApi.create_vendor :vendor => {:name => 'Test'} # will auto-login for you, if you're not already logged in
|
16
|
+
vendor.result.inspect => #<BillApi::RequestResult transactionId="Transaction1", status="OK", id="xxy">
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'loco_bill'
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module LocoBill
|
2
|
+
class Request
|
3
|
+
attr_accessor :result
|
4
|
+
@@api_domain = 'api.bill.com'
|
5
|
+
@@api_endpoint = "/crudApi"
|
6
|
+
@@session_id = nil
|
7
|
+
@@transaction_id = 0
|
8
|
+
NON_OPERATION_WRAPPED_ACTIONS = [:login, :logout, :getorglist]
|
9
|
+
INLINE_PARAMS_ACTIONS = {:get_list => :object}
|
10
|
+
|
11
|
+
def initialize(action, params={})
|
12
|
+
@action = action.to_sym
|
13
|
+
# auto-login & grab session id if we don't already have one.
|
14
|
+
if @@session_id.nil? && @action != :login
|
15
|
+
@@session_id = LocoBill.login.result.sessionId
|
16
|
+
end
|
17
|
+
@params = params
|
18
|
+
@result = process_response(api(build_request_xml))
|
19
|
+
end
|
20
|
+
|
21
|
+
def build_request_xml
|
22
|
+
operation_wrapped = !NON_OPERATION_WRAPPED_ACTIONS.include?(@action)
|
23
|
+
|
24
|
+
Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
25
|
+
xml.request(:version => '1.0', :applicationkey => BILL_API_APPLICATION_KEY) {
|
26
|
+
if operation_wrapped
|
27
|
+
# gotta wrap most of the api calls in an "operation" block with a transaction id & session id
|
28
|
+
xml.operation(:transactionId => transaction_id, :sessionId => @@session_id) { action_xml(xml) }
|
29
|
+
else
|
30
|
+
action_xml(xml)
|
31
|
+
end
|
32
|
+
}
|
33
|
+
end.to_xml
|
34
|
+
end
|
35
|
+
|
36
|
+
# called from build_request_xml, just the xml related to the action we're doing
|
37
|
+
# TODO: refactor into a method that takes a wrapper &block
|
38
|
+
def action_xml(xml)
|
39
|
+
inline_params = INLINE_PARAMS_ACTIONS.has_key?(@action) ? {INLINE_PARAMS_ACTIONS[@action] => @params[INLINE_PARAMS_ACTIONS[@action]]} : nil
|
40
|
+
xml.send(@action, inline_params) do
|
41
|
+
params_xml(xml, @params)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# recursive, so you can do things like:
|
46
|
+
# BillApi.create_vendor :vendor => {:name => 'Test'}
|
47
|
+
def params_xml(xml, params)
|
48
|
+
params.each do |k, v|
|
49
|
+
if v.is_a?(Hash)
|
50
|
+
xml.send(k) { params_xml(xml, v) }
|
51
|
+
else
|
52
|
+
xml.send(k) { xml.text(v) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# generate a transaction id for operation requests
|
58
|
+
def transaction_id
|
59
|
+
@@transaction_id += 1
|
60
|
+
"Transaction#{@@transaction_id}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def api(xml_body)
|
64
|
+
# puts "XML BODY: #{xml_body}"
|
65
|
+
https = Net::HTTP.new(@@api_domain, 443)
|
66
|
+
https.use_ssl = true
|
67
|
+
https.read_timeout=5 # 5 second timeout
|
68
|
+
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
69
|
+
req = Net::HTTP::Post.new(@@api_endpoint)
|
70
|
+
req.body = "request=#{req.send(:urlencode, xml_body)}" # prefixing the request with "request=" showed up in the docs absolutely nowhere. thanks, bill.com.
|
71
|
+
req.content_type = 'application/x-www-form-urlencoded'
|
72
|
+
|
73
|
+
resp = https.start {|http|
|
74
|
+
http.request(req)
|
75
|
+
}
|
76
|
+
case resp
|
77
|
+
when Net::HTTPSuccess
|
78
|
+
resp.body
|
79
|
+
else
|
80
|
+
resp.error!
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def process_response(raw_response)
|
85
|
+
# puts "RAW RESPONSE: #{raw_response}"
|
86
|
+
res = Hash.from_xml(raw_response)['response']
|
87
|
+
res = res["#{@action}result"] || res["operationresult"]
|
88
|
+
res.symbolize_keys!
|
89
|
+
|
90
|
+
if res[:status] == 'OK'
|
91
|
+
RequestResult.new(res)
|
92
|
+
else
|
93
|
+
raise RequestError.new "#{res[:errorcode]}: #{res[:errormessage]}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class RequestResult < OpenStruct; end
|
99
|
+
class RequestError < StandardError; end
|
100
|
+
end
|
data/lib/loco_bill.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'bill_api/request'
|
4
|
+
require 'bill_api/login'
|
5
|
+
|
6
|
+
module LocoBill
|
7
|
+
# might not be 100% correct
|
8
|
+
ALLOWED_METHODS = [:login, :logout, :getorglist, :operationbatch, :filter, :expression, :get_list, :org_info, :pay_bill, :vendor, :create_vendor, :update_vendor, :create_chartofaccount, :update_chartofaccount, :create_department, :update_department, :create_job, :update_job, :billpay, :bill, :billLineItem, :billLineItems, :create_bill, :chartOfAccount, :department, :job, :upload_document]
|
9
|
+
|
10
|
+
def self.method_missing(m, *args, &block)
|
11
|
+
ALLOWED_METHODS.include?(m) ? Request.new(m, *args) : super
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: loco_bill
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- chris mcc
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-06-14 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.3.3
|
24
|
+
version:
|
25
|
+
description: A ruby wrapper for interacting with Bill.com's developer API
|
26
|
+
email:
|
27
|
+
- cmcclelland@digitaladvisor.com
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files: []
|
33
|
+
|
34
|
+
files:
|
35
|
+
- lib/loco_bill/login.rb
|
36
|
+
- lib/loco_bill/request.rb
|
37
|
+
- lib/loco_bill.rb
|
38
|
+
- README
|
39
|
+
- init.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/DigitalAdvisor/loco_bill
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --main
|
47
|
+
- README
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: loco_bill
|
65
|
+
rubygems_version: 1.3.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: A ruby wrapper for interacting with Bill.com's developer API
|
69
|
+
test_files: []
|
70
|
+
|