quickbooks 0.9.9 → 1.0.2
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.tar.gz.sig +0 -0
- data/Manifest.txt +0 -1
- data/README.txt +1 -1
- data/lib/quickbooks/adapters/https_adapter.rb +9 -9
- data/lib/quickbooks/element_collection.rb +7 -2
- data/lib/quickbooks/model.rb +15 -4
- data/lib/quickbooks/ruby_ext.rb +6 -5
- data/lib/quickbooks/version.rb +4 -4
- data/lib/quickbooks/xsd/complex_type.rb +9 -1
- metadata +1 -2
- metadata.gz.sig +0 -0
- data/lib/quickbooks/adapters/tcp_adapter.rb +0 -71
data.tar.gz.sig
CHANGED
Binary file
|
data/Manifest.txt
CHANGED
@@ -9,7 +9,6 @@ lib/quickbooks/adapters/http_adapter.rb
|
|
9
9
|
lib/quickbooks/adapters/https_adapter.rb
|
10
10
|
lib/quickbooks/adapters/ole_adapter.rb
|
11
11
|
lib/quickbooks/adapters/spew_adapter.rb
|
12
|
-
lib/quickbooks/adapters/tcp_adapter.rb
|
13
12
|
lib/quickbooks/adapters/test_adapter.rb
|
14
13
|
lib/quickbooks/element.rb
|
15
14
|
lib/quickbooks/element_collection.rb
|
data/README.txt
CHANGED
@@ -9,7 +9,7 @@ The only comprehensive Ruby interface to Quickbooks. THIS IS A DEMO VERSION. Vis
|
|
9
9
|
|
10
10
|
== SYNOPSIS:
|
11
11
|
|
12
|
-
jim = QB::Customer.first(:
|
12
|
+
jim = QB::Customer.first(:FullName => "Jim Stout")
|
13
13
|
jim.destroy # Note that you cannot delete items in QuickBooks
|
14
14
|
# but you CAN delete them using the API.
|
15
15
|
|
@@ -18,18 +18,18 @@ module Quickbooks
|
|
18
18
|
class Connection < HttpAdapter::Connection
|
19
19
|
private
|
20
20
|
def new_connection
|
21
|
-
root_ca_file = '/
|
21
|
+
# root_ca_file = File.dirname(__FILE__) + '/cacert.pem'
|
22
22
|
http = Net::HTTP.new(@ip, @port)
|
23
23
|
http.use_ssl = true
|
24
|
-
if File.exist?(root_ca_file)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
else
|
24
|
+
# if File.exist?(root_ca_file)
|
25
|
+
# http.ca_file = root_ca_file
|
26
|
+
# http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
27
|
+
# # http.verify_depth = 5
|
28
|
+
# http.verify_depth = 5
|
29
|
+
# http.enable_post_connection_check = false #true
|
30
|
+
# else
|
31
31
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
32
|
-
end
|
32
|
+
# end
|
33
33
|
http
|
34
34
|
end
|
35
35
|
end
|
@@ -59,7 +59,6 @@ class ElementCollection
|
|
59
59
|
# TODO: Has a problem when an element is a new_record and a child isn't, or vice-versa.
|
60
60
|
def to_element #:nodoc:
|
61
61
|
element_klass = @type < Quickbooks::Model ? (@type.short_name + (@parent.new_record? ? 'Add' : 'Mod')) : @type.short_name
|
62
|
-
puts "Converting to #{element_klass}"
|
63
62
|
elements = ElementCollection.new(@parent, element_klass)
|
64
63
|
items.each {|e| elements << (@type < Quickbooks::Model ? e.to_element : e)}
|
65
64
|
return elements
|
@@ -89,7 +88,11 @@ class ElementCollection
|
|
89
88
|
|
90
89
|
def add_item(item)
|
91
90
|
item = @type.new(item) unless item.is_a?(@type)
|
92
|
-
|
91
|
+
if dirty?
|
92
|
+
item.send(:dirty!)
|
93
|
+
elsif item.dirty?
|
94
|
+
dirty!
|
95
|
+
end
|
93
96
|
items << item
|
94
97
|
return item
|
95
98
|
end
|
@@ -101,5 +104,7 @@ class ElementCollection
|
|
101
104
|
|
102
105
|
def dirty!
|
103
106
|
@dirty = true
|
107
|
+
# Shall all items be declared dirty when the collection container becomes dirty?
|
108
|
+
# items.each {|e| e.send(:dirty!)}
|
104
109
|
end
|
105
110
|
end
|
data/lib/quickbooks/model.rb
CHANGED
@@ -308,9 +308,14 @@ module Quickbooks
|
|
308
308
|
attributes[key] = ElementCollection.new(self, key, value)
|
309
309
|
attributes[key].send(:dirty!)
|
310
310
|
else
|
311
|
-
|
312
|
-
|
313
|
-
|
311
|
+
if attributes[key].nil? || attributes[key].empty?
|
312
|
+
attributes[key] = ElementCollection.new(self, key, [value])
|
313
|
+
attributes[key].send(:dirty!)
|
314
|
+
else
|
315
|
+
# If it *should* be an array element, it shouldn't be set here as a single value. This is just for safeguard, so that syntax
|
316
|
+
# always shows what is going on. For an array element, set it with: object.some_attr = [value]
|
317
|
+
raise RuntimeError, "You can't set a singular value directly over an element that already contains multiple values. Use \"model[:#{key}] << value\" to append, or wrap the value in an array to explicitly replace the current contents -- \"model[:#{key}] = [ value ]\"."
|
318
|
+
end
|
314
319
|
end
|
315
320
|
else
|
316
321
|
value = @new_record.nil? ? attr_klass.instantiate(value) : attr_klass.new(value) unless value.is_a?(attr_klass)
|
@@ -518,8 +523,14 @@ module Quickbooks
|
|
518
523
|
|
519
524
|
def associate(association_name, value)
|
520
525
|
instance_variable_set("@#{association_name}", value)
|
521
|
-
ref = value.to_ref
|
522
526
|
ref_klass = self.class.associations[association_name].klass
|
527
|
+
ref = if value.respond_to?(:to_ref)
|
528
|
+
value.to_ref
|
529
|
+
elsif value.respond_to?(:[]) && !value.is_a?(Array)
|
530
|
+
ref_klass.new(value)
|
531
|
+
else
|
532
|
+
raise ArgumentError, "To assign to #{association_name}, set to a #{ref_klass} object or a Hash with the appropriate values to create one."
|
533
|
+
end
|
523
534
|
!ref.nil? ?
|
524
535
|
self[ref_klass] = ref :
|
525
536
|
self.delete(ref_klass)
|
data/lib/quickbooks/ruby_ext.rb
CHANGED
@@ -57,11 +57,11 @@ class String
|
|
57
57
|
def xml_escaped
|
58
58
|
gsub(/[&<>'"]/) {|match|
|
59
59
|
case match
|
60
|
-
when '&' then
|
61
|
-
when '<' then
|
62
|
-
when '>' then
|
63
|
-
when "'" then
|
64
|
-
when '"' then
|
60
|
+
when '&' then '&'
|
61
|
+
when '<' then '<'
|
62
|
+
when '>' then '>'
|
63
|
+
when "'" then '''
|
64
|
+
when '"' then '"e;'
|
65
65
|
end
|
66
66
|
}
|
67
67
|
end
|
@@ -154,6 +154,7 @@ module Quickbooks
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
obj = stack.pop
|
157
|
+
raise RuntimeError, "Error while parsing xml response. XML:\n#{xml}" if obj.nil?
|
157
158
|
obj.send(:clean!)
|
158
159
|
obj
|
159
160
|
end
|
data/lib/quickbooks/version.rb
CHANGED
@@ -35,7 +35,15 @@ module Quickbooks
|
|
35
35
|
def validate(object,required=true)
|
36
36
|
# Validate the object's contents
|
37
37
|
puts "#{$DEBUG<<"\t"}Validating CONFORMS TO #ComplexType #{name} (#{required ? 'REQUIRED' : 'OPTIONAL'})" if $DEBUG
|
38
|
-
|
38
|
+
# If the object's contents are Enumerable (multiple values), we'll have to validate each of them individually
|
39
|
+
# and return the combined result of all of their validations.
|
40
|
+
r = if object.is_a?(Enumerable) && !object.is_a?(Hash)
|
41
|
+
object.inject(Valean.new) do |r,obj|
|
42
|
+
items.inject(r) {|r,i| r << i.validate(obj,required?(i)); r}
|
43
|
+
end
|
44
|
+
else
|
45
|
+
items.inject(Valean.new) {|r,i| r << i.validate(object,required?(i)); r}
|
46
|
+
end
|
39
47
|
$DEBUG.chop! if $DEBUG
|
40
48
|
puts "#{$DEBUG}\t- #{r}" if $DEBUG
|
41
49
|
r
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quickbooks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- BehindLogic
|
@@ -67,7 +67,6 @@ files:
|
|
67
67
|
- lib/quickbooks/adapters/https_adapter.rb
|
68
68
|
- lib/quickbooks/adapters/ole_adapter.rb
|
69
69
|
- lib/quickbooks/adapters/spew_adapter.rb
|
70
|
-
- lib/quickbooks/adapters/tcp_adapter.rb
|
71
70
|
- lib/quickbooks/adapters/test_adapter.rb
|
72
71
|
- lib/quickbooks/element.rb
|
73
72
|
- lib/quickbooks/element_collection.rb
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
|
3
|
-
# THIS IS A LEGACY ADAPTER, ITS USE IS NOT RECOMMENDED! It is insecure and unstable.
|
4
|
-
# This adapter sends QBXML via an HTTP connection which is kept open for each session, and expects intelligent real-time QB responses from the other end.
|
5
|
-
module Quickbooks
|
6
|
-
module Adapters
|
7
|
-
module HttpAdapter
|
8
|
-
# Whatever we do here, we just have to be sure that decrypt(encrypt(data)) == data
|
9
|
-
module SimpleEncryption
|
10
|
-
def encrypt(data)
|
11
|
-
data
|
12
|
-
end
|
13
|
-
|
14
|
-
def decrypt(data)
|
15
|
-
data
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class Connection
|
20
|
-
include SimpleEncryption
|
21
|
-
def initialize(ip, port, shared_key)
|
22
|
-
@ip = ip
|
23
|
-
@port = port
|
24
|
-
@shared_key = shared_key
|
25
|
-
end
|
26
|
-
|
27
|
-
# Returns true if there is an open connection to Quickbooks, false if not. Use session? to determine an open session.
|
28
|
-
def connected?
|
29
|
-
(@connection ||= new_connection).started?
|
30
|
-
end
|
31
|
-
|
32
|
-
def close
|
33
|
-
@connection.finish rescue nil
|
34
|
-
end
|
35
|
-
|
36
|
-
# Sends a request to Quickbooks. This request should be a valid QBXML request. Use Qbxml::Request to generate valid requests.
|
37
|
-
def send_xml(xml)
|
38
|
-
# TODO: request.basic_auth url.user, url.password
|
39
|
-
res = try_retry(1, EOFError, :before_retry => lambda {@connection.finish}) {
|
40
|
-
connection.post('/ProcessRequest', encrypt(xml), {'Content-Type' => 'application/xml'})
|
41
|
-
}
|
42
|
-
response = decrypt(res.body)
|
43
|
-
return response
|
44
|
-
# rescue => e
|
45
|
-
# Rescue from the error: I guess we have to return a pretend response that says the network failed.
|
46
|
-
# raise "Failsafe not yet implemented!: #{e.inspect}"
|
47
|
-
end
|
48
|
-
|
49
|
-
def qbxml_versions
|
50
|
-
res = try_retry(1, EOFError, :before_retry => lambda {@connection.finish}) { connection.get('/QBXMLVersionsForSession') }
|
51
|
-
response = decrypt(res.body)
|
52
|
-
return response.chomp.split(/,/)
|
53
|
-
end
|
54
|
-
def latest_qbxml_version
|
55
|
-
@latest_qbxml_version ||= qbxml_versions.sort.last
|
56
|
-
end
|
57
|
-
|
58
|
-
# Returns the active connection to Quickbooks, or creates a new one if none exists.
|
59
|
-
def connection
|
60
|
-
@connection.start unless connected?
|
61
|
-
@connection
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
def new_connection
|
66
|
-
Net::HTTP.new(@ip, @port)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|