quickeebooks 0.0.8 → 0.0.9
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/Gemfile.lock +1 -1
- data/README.md +93 -15
- data/lib/quickeebooks/online/model/invoice_header.rb +1 -0
- data/lib/quickeebooks/version.rb +1 -1
- data/lib/quickeebooks/windows/model/address.rb +1 -1
- data/lib/quickeebooks/windows/model/customer.rb +1 -1
- data/lib/quickeebooks/windows/model/phone.rb +1 -1
- data/lib/quickeebooks/windows/service/customer.rb +34 -0
- data/spec/quickeebooks/windows/services/customer_spec.rb +20 -0
- data/spec/xml/windows/customer_update_success.xml +13 -0
- data/tmp/create_customer_windows.rb +19 -1
- metadata +3 -2
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -22,22 +22,69 @@ Gems:
|
|
22
22
|
* `nokogiri` : XML parsing
|
23
23
|
* `active_model` : For validations
|
24
24
|
|
25
|
-
## Getting Started
|
25
|
+
## Getting Started & Initiating Authentication Flow with Intuit
|
26
26
|
|
27
|
-
|
27
|
+
What follows is an example using Rails but the principles can be adapted to any other framework / pure Ruby.
|
28
|
+
|
29
|
+
Create a Rails initializer with:
|
28
30
|
|
29
31
|
```ruby
|
30
|
-
QB_KEY = "your
|
31
|
-
QB_SECRET = "your
|
32
|
+
QB_KEY = "your apps Intuit App Key"
|
33
|
+
QB_SECRET = "your apps Intuit Secret Key"
|
32
34
|
|
33
|
-
qb_oauth_consumer = OAuth::Consumer.new(QB_KEY, QB_SECRET, {
|
35
|
+
$qb_oauth_consumer = OAuth::Consumer.new(QB_KEY, QB_SECRET, {
|
34
36
|
:site => "https://oauth.intuit.com",
|
35
37
|
:request_token_path => "/oauth/v1/get_request_token",
|
36
38
|
:authorize_url => "https://appcenter.intuit.com/Connect/Begin",
|
37
39
|
:access_token_path => "/oauth/v1/get_access_token"
|
38
40
|
})
|
41
|
+
```
|
42
|
+
|
43
|
+
To start the authentication flow with Intuit you include the Intuit Javascript and on a page of your choosing you present the "Connect to Quickbooks" button by including this XHTML:
|
44
|
+
|
45
|
+
|
46
|
+
```HTML
|
47
|
+
<!-- somewhere in your document include the Javascript -->
|
48
|
+
<script type="text/javascript" src="https://appcenter.intuit.com/Content/IA/intuit.ipp.anywhere.js"></script>
|
49
|
+
|
50
|
+
<!-- configure the Intuit object: 'grantUrl' is a URL in your application which kicks off the flow, see below -->
|
51
|
+
<script>
|
52
|
+
intuit.ipp.anywhere.setup({menuProxy: '/path/to/blue-dot', grantUrl: '/path/to/your-flow-start'});
|
53
|
+
</script>
|
54
|
+
|
55
|
+
<!-- this will display a button that the user clicks to start the flow -->
|
56
|
+
<ipp:connectToIntuit></ipp:connectToIntuit>
|
57
|
+
```
|
58
|
+
|
59
|
+
Your Controller action (the `grantUrl` above) should look like this:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
def authenticate
|
63
|
+
callback = quickbooks_oauth_callback_url
|
64
|
+
token = $qb_oauth_consumer.get_request_token(:oauth_callback => callback)
|
65
|
+
session[:qb_request_token] = token
|
66
|
+
redirect_to("https://appcenter.intuit.com/Connect/Begin?oauth_token=#{token.token}") and return
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
Where `quickbooks_oauth_callback_url` is the absolute URL of your application that Intuit should send the user when authentication succeeeds. That action should look like:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
def oauth_callback
|
74
|
+
at = session[:qb_request_token].get_access_token(:oauth_verifier => params[:oauth_verifier])
|
75
|
+
token = at.token
|
76
|
+
secret = at.secret
|
77
|
+
realm_id = params['realmId']
|
78
|
+
# store the token, secret & RealmID somewhere for this user, you will need all 3 to work with Quickeebooks
|
79
|
+
end
|
80
|
+
```
|
39
81
|
|
40
|
-
|
82
|
+
## Creating an OAuth Access Token
|
83
|
+
|
84
|
+
Once you have your users OAuth Token & Secret you can initialize your `OAuth Consumer` and create a `OAuth Client` using the `$qb_oauth_consumer` you created earlier in your Rails initializer:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
oauth_client = OAuth::AccessToken.new($qb_oauth_consumer, access_token, access_secret)
|
41
88
|
```
|
42
89
|
|
43
90
|
## Quickbooks Online vs Windows
|
@@ -46,17 +93,21 @@ IDS provides 2 APIs, one for interacting with Quickbooks Online resources and on
|
|
46
93
|
|
47
94
|
See: https://ipp.developer.intuit.com/0010_Intuit_Partner_Platform/0050_Data_Services
|
48
95
|
|
49
|
-
|
96
|
+
You will need to be aware of which flavor of the API you want to invoke.
|
50
97
|
|
51
98
|
For example:
|
52
99
|
|
53
100
|
```ruby
|
54
101
|
# Instantiate a Online API
|
55
|
-
customer_service = Quickeebooks::Online::Service::Customer.new
|
102
|
+
customer_service = Quickeebooks::Online::Service::Customer.new
|
103
|
+
customer_service.access_token = oauth_client
|
104
|
+
customer_service.realm_id = realm_id
|
56
105
|
customer_service.list
|
57
106
|
|
58
107
|
# Instantiate a Windows API
|
59
108
|
customer_service = Quickeebooks::Windows::Service::Customer.new(oauth_client, realm_id)
|
109
|
+
customer_service.access_token = oauth_client
|
110
|
+
customer_service.realm_id = realm_id
|
60
111
|
customer_service.list
|
61
112
|
```
|
62
113
|
|
@@ -65,7 +116,10 @@ All of the documentation below is geared towards the Online flavor but unless no
|
|
65
116
|
Now we can initialize any of the `Service` clients:
|
66
117
|
|
67
118
|
```ruby
|
68
|
-
customer_service = Quickeebooks::Online::Service::Customer.new
|
119
|
+
customer_service = Quickeebooks::Online::Service::Customer.new
|
120
|
+
customer_service.access_token = oauth_client
|
121
|
+
customer_service.realm_id = realm_id
|
122
|
+
customer_service.list
|
69
123
|
customer_service.list
|
70
124
|
|
71
125
|
# returns a `Collection` object
|
@@ -99,7 +153,11 @@ Pass a `Sort` object for any desired sorting or just let Intuit use the default
|
|
99
153
|
Specify none of these to get the defaults:
|
100
154
|
|
101
155
|
```ruby
|
102
|
-
customer_service = Quickeebooks::Online::Service::Customer.new
|
156
|
+
customer_service = Quickeebooks::Online::Service::Customer.new
|
157
|
+
customer_service.access_token = oauth_client
|
158
|
+
customer_service.realm_id = realm_id
|
159
|
+
customer_service.list
|
160
|
+
|
103
161
|
# fetch all customers with default parameters (pagination, sorting, filtering)
|
104
162
|
customers = customer_service.list
|
105
163
|
```
|
@@ -172,7 +230,11 @@ filters = []
|
|
172
230
|
filters << Quickeebooks::Online::Service::Filter.new(:text, :field => 'FamilyName', :value => 'Richards')
|
173
231
|
datetime = Time.mktime(2011, 2, 25)
|
174
232
|
filters << Quickeebooks::Online::Service::Filter.new(:datetime, :field => 'CreateTime', :before => datetime)
|
175
|
-
customer_service = Quickeebooks::Online::Service::Customer.new
|
233
|
+
customer_service = Quickeebooks::Online::Service::Customer.new
|
234
|
+
customer_service.access_token = oauth_client
|
235
|
+
customer_service.realm_id = realm_id
|
236
|
+
customer_service.list
|
237
|
+
|
176
238
|
customers = customer_service.list(filters)
|
177
239
|
```
|
178
240
|
## Sorting (currently only supported in the Online API)
|
@@ -201,7 +263,11 @@ filters << Quickeebooks::Online::Service::Filter.new(:datetime, :field => 'Creat
|
|
201
263
|
|
202
264
|
sorter = Quickeebooks::Online::Service::Sort.new('FamilyName', 'AtoZ')
|
203
265
|
|
204
|
-
customer_service = Quickeebooks::Online::Service::Customer.new
|
266
|
+
customer_service = Quickeebooks::Online::Service::Customer.new
|
267
|
+
customer_service.access_token = oauth_client
|
268
|
+
customer_service.realm_id = realm_id
|
269
|
+
customer_service.list
|
270
|
+
|
205
271
|
customers = customer_service.list(filters, 1, 30, sort)
|
206
272
|
|
207
273
|
# returns
|
@@ -222,7 +288,11 @@ Use the `Service` instance to fetch an object by its id using the `fetch_by_id`
|
|
222
288
|
|
223
289
|
```ruby
|
224
290
|
# fetch the Customer object with an id of 100
|
225
|
-
customer_service = Quickeebooks::Online::Service::Customer.new
|
291
|
+
customer_service = Quickeebooks::Online::Service::Customer.new
|
292
|
+
customer_service.access_token = oauth_client
|
293
|
+
customer_service.realm_id = realm_id
|
294
|
+
customer_service.list
|
295
|
+
|
226
296
|
customer = customer_service.fetch_by_id(100)
|
227
297
|
customer.name
|
228
298
|
=> John Doe
|
@@ -239,7 +309,11 @@ You will need make sure you supply all required fields for that Intuit object, s
|
|
239
309
|
Pass an instance of your object to the `create` method on its related Service:
|
240
310
|
|
241
311
|
```ruby
|
242
|
-
customer_service = Quickeebooks::Online::Service::Customer.new
|
312
|
+
customer_service = Quickeebooks::Online::Service::Customer.new
|
313
|
+
customer_service.access_token = oauth_client
|
314
|
+
customer_service.realm_id = realm_id
|
315
|
+
customer_service.list
|
316
|
+
|
243
317
|
customer = Quickeebooks::Online::Model::Customer.new
|
244
318
|
customer.name = "Richard Parker"
|
245
319
|
customer.email = "richard@example.org"
|
@@ -253,7 +327,11 @@ customer_service.create(customer)
|
|
253
327
|
Pass an instance of your object to the `update` method on its related Service:
|
254
328
|
|
255
329
|
```ruby
|
256
|
-
customer_service = Quickeebooks::Online::Service::Customer.new
|
330
|
+
customer_service = Quickeebooks::Online::Service::Customer.new
|
331
|
+
customer_service.access_token = oauth_client
|
332
|
+
customer_service.realm_id = realm_id
|
333
|
+
customer_service.list
|
334
|
+
|
257
335
|
customer = customer_service.fetch_by_id(100)
|
258
336
|
customer.name = "Richard Parker"
|
259
337
|
customer.email = "richard@example.org"
|
@@ -17,6 +17,7 @@ module Quickeebooks
|
|
17
17
|
xml_accessor :sales_tax_code_name, :from => 'SalesTaxCodeName'
|
18
18
|
xml_accessor :sub_total_amount, :from => 'SubTotalAmt', :as => Float
|
19
19
|
xml_accessor :tax_rate, :from => 'TaxRate', :as => Float
|
20
|
+
xml_accessor :tax_amount, :from => 'TaxAmt', :as => Float
|
20
21
|
xml_accessor :balance, :from => 'Balance', :as => Float
|
21
22
|
xml_accessor :total_amount, :from => 'TotalAmt', :as => Float
|
22
23
|
xml_accessor :due_date, :from => 'DueDate', :as => Time
|
data/lib/quickeebooks/version.rb
CHANGED
@@ -15,8 +15,8 @@ module Quickeebooks
|
|
15
15
|
xml_accessor :country_sub_division_code, :from => 'CountrySubDivisionCode'
|
16
16
|
xml_accessor :postal_code, :from => 'PostalCode'
|
17
17
|
xml_accessor :postal_code_suffix, :from => 'PostalCodeSuffix'
|
18
|
-
xml_accessor :tag, :from => 'Tag'
|
19
18
|
xml_accessor :default, :from => 'Default'
|
19
|
+
xml_accessor :tag, :from => 'Tag'
|
20
20
|
|
21
21
|
def zip
|
22
22
|
postal_code
|
@@ -34,9 +34,9 @@ module Quickeebooks
|
|
34
34
|
xml_accessor :type_of, :from => 'TypeOf'
|
35
35
|
xml_accessor :name, :from => 'Name'
|
36
36
|
xml_accessor :addresses, :from => 'Address', :as => [Quickeebooks::Windows::Model::Address]
|
37
|
-
xml_accessor :email, :from => 'Email', :as => Quickeebooks::Windows::Model::Email
|
38
37
|
xml_accessor :phones, :from => 'Phone', :as => [Quickeebooks::Windows::Model::Phone]
|
39
38
|
xml_accessor :web_site, :from => 'WebSite', :as => Quickeebooks::Windows::Model::WebSite
|
39
|
+
xml_accessor :email, :from => 'Email', :as => Quickeebooks::Windows::Model::Email
|
40
40
|
xml_accessor :title, :from => 'Title'
|
41
41
|
xml_accessor :given_name, :from => 'GivenName'
|
42
42
|
xml_accessor :middle_name, :from => 'MiddleName'
|
@@ -7,8 +7,8 @@ module Quickeebooks
|
|
7
7
|
xml_accessor :id, :from => 'Id'
|
8
8
|
xml_accessor :device_type, :from => 'DeviceType'
|
9
9
|
xml_accessor :free_form_number, :from => 'FreeFormNumber'
|
10
|
-
xml_accessor :tag, :from => 'Tag'
|
11
10
|
xml_accessor :default, :from => 'Default'
|
11
|
+
xml_accessor :tag, :from => 'Tag'
|
12
12
|
|
13
13
|
def default?
|
14
14
|
default == "true"
|
@@ -32,7 +32,41 @@ module Quickeebooks
|
|
32
32
|
</Add>
|
33
33
|
XML
|
34
34
|
perform_write(Quickeebooks::Windows::Model::Customer, xml)
|
35
|
+
end
|
36
|
+
|
37
|
+
def update(customer)
|
38
|
+
# XML is a wrapped 'object' where the type is specified as an attribute
|
39
|
+
# <Object xsi:type="Invoice">
|
40
|
+
|
41
|
+
# Intuit requires that some fields are unset / do not exist.
|
42
|
+
customer.meta_data = nil
|
43
|
+
customer.external_key = nil
|
44
|
+
|
45
|
+
# unset Id fields in addresses, phones, email
|
46
|
+
if customer.addresses
|
47
|
+
customer.addresses.each {|address| address.id = nil }
|
48
|
+
end
|
49
|
+
if customer.email
|
50
|
+
customer.email.id = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
if customer.phones
|
54
|
+
customer.phones.each {|phone| phone.id = nil }
|
55
|
+
end
|
56
|
+
|
57
|
+
if customer.web_site
|
58
|
+
customer.web_site.id = nil
|
59
|
+
end
|
35
60
|
|
61
|
+
xml_node = customer.to_xml(:name => 'Object')
|
62
|
+
xml_node.set_attribute('xsi:type', 'Customer')
|
63
|
+
xml = <<-XML
|
64
|
+
<Mod xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" RequestId="#{guid}" xmlns="http://www.intuit.com/sb/cdm/v2">
|
65
|
+
<ExternalRealmId>#{self.realm_id}</ExternalRealmId>
|
66
|
+
#{xml_node}
|
67
|
+
</Mod>
|
68
|
+
XML
|
69
|
+
perform_write(Quickeebooks::Windows::Model::Customer, xml)
|
36
70
|
end
|
37
71
|
|
38
72
|
end
|
@@ -153,6 +153,26 @@ describe "Quickeebooks::Windows::Service::Customer" do
|
|
153
153
|
create_response.success.party_role_ref.id.value.should == "6762304"
|
154
154
|
create_response.success.request_name.should == "CustomerAdd"
|
155
155
|
end
|
156
|
+
|
157
|
+
it "can update a customer name" do
|
158
|
+
customer_xml = File.read(File.dirname(__FILE__) + "/../../../xml/windows/customer.xml")
|
159
|
+
update_response_xml = File.read(File.dirname(__FILE__) + "/../../../xml/windows/customer_update_success.xml")
|
160
|
+
service = Quickeebooks::Windows::Service::Customer.new
|
161
|
+
model = Quickeebooks::Windows::Model::Customer
|
162
|
+
customer = model.from_xml(customer_xml)
|
163
|
+
customer.name.should == "Wine House"
|
164
|
+
|
165
|
+
service.access_token = @oauth
|
166
|
+
service.realm_id = @realm_id
|
167
|
+
FakeWeb.register_uri(:post, service.url_for_resource(model::REST_RESOURCE), :status => ["200", "OK"], :body => update_response_xml)
|
168
|
+
|
169
|
+
# change the name
|
170
|
+
customer.name = "Acme Cafe"
|
171
|
+
update_response = service.update(customer)
|
172
|
+
update_response.success?.should == true
|
173
|
+
update_response.success.party_role_ref.id.value.should == "6762304"
|
174
|
+
update_response.success.request_name.should == "CustomerMod"
|
175
|
+
end
|
156
176
|
|
157
177
|
|
158
178
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<RestResponse xmlns="http://www.intuit.com/sb/cdm/v2">
|
3
|
+
<Success RequestId="1b405391016149c593c005e45700dd01">
|
4
|
+
<PartyRoleRef>
|
5
|
+
<Id idDomain="NG">6762304</Id>
|
6
|
+
<SyncToken>7</SyncToken>
|
7
|
+
<LastUpdatedTime>2012-11-29T01:01:47Z</LastUpdatedTime>
|
8
|
+
<PartyReferenceId idDomain="NG">6170150</PartyReferenceId>
|
9
|
+
</PartyRoleRef>
|
10
|
+
<RequestName>CustomerMod</RequestName>
|
11
|
+
<ProcessedTime>2012-11-29T01:01:47Z</ProcessedTime>
|
12
|
+
</Success>
|
13
|
+
</RestResponse>
|
@@ -3,6 +3,7 @@ require 'oauth'
|
|
3
3
|
$: << File.expand_path('./lib')
|
4
4
|
require 'quickeebooks'
|
5
5
|
|
6
|
+
# attached to "Vinosmith.qbw" in Quickbooks Simple Start 2010
|
6
7
|
consumer_key = 'qyprdL8NUDMYcCzwp8ea9KbIhaMSRk'
|
7
8
|
consumer_secret = 'FcE5kihBYMVQGvX9UNYMxsrM8mP7bfuxc36PLhJB'
|
8
9
|
qb_oauth_consumer = OAuth::Consumer.new(consumer_key, consumer_secret, {
|
@@ -22,6 +23,22 @@ service = Quickeebooks::Windows::Service::Customer.new
|
|
22
23
|
service.access_token = oauth
|
23
24
|
service.realm_id = realm_id
|
24
25
|
|
26
|
+
customer = service.fetch_by_id(1)
|
27
|
+
puts customer.name
|
28
|
+
if customer.notes
|
29
|
+
customer.notes.each { |note| puts note.content }
|
30
|
+
end
|
31
|
+
# UPDATE it
|
32
|
+
customer.name = "Cody 22 TEST"
|
33
|
+
|
34
|
+
customer.meta_data = nil
|
35
|
+
customer.external_key = nil
|
36
|
+
|
37
|
+
response = service.update(customer)
|
38
|
+
#puts response.inspect
|
39
|
+
|
40
|
+
#puts service.list
|
41
|
+
=begin
|
25
42
|
customer = Quickeebooks::Windows::Model::Customer.new
|
26
43
|
customer.type_of = "Person"
|
27
44
|
customer.name = "Cody Test-#{Time.now.to_i}"
|
@@ -38,4 +55,5 @@ billing_address.postal_code = "94117"
|
|
38
55
|
billing_address.country = "USA"
|
39
56
|
customer.address = billing_address
|
40
57
|
result = service.create(customer)
|
41
|
-
puts result.inspect
|
58
|
+
puts result.inspect
|
59
|
+
=end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quickeebooks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: roxml
|
@@ -325,6 +325,7 @@ files:
|
|
325
325
|
- spec/xml/windows/company_meta_data.xml
|
326
326
|
- spec/xml/windows/customer.xml
|
327
327
|
- spec/xml/windows/customer_create_success.xml
|
328
|
+
- spec/xml/windows/customer_update_success.xml
|
328
329
|
- spec/xml/windows/customers.xml
|
329
330
|
- spec/xml/windows/fetch_customer_by_id.xml
|
330
331
|
- spec/xml/windows/http_401.xml
|