loco_bill 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|