class Quickeebooks::Windows::Service::ServiceBase
Constants
- XML_NS
Attributes
base_uri[R]
last_response_body[R]
last_response_xml[R]
oauth[RW]
realm_id[RW]
Public Class Methods
new(oauth_access_token = nil, realm_id = nil)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 28 def initialize(oauth_access_token = nil, realm_id = nil) @base_uri = 'https://services.intuit.com/sb' if !oauth_access_token.nil? && !realm_id.nil? msg = "Quickeebooks::Windows::ServiceBase - " msg += "This version of the constructor is deprecated. " msg += "Use the no-arg constructor and set the AccessToken and the RealmID using the accessors." warn(msg) access_token = oauth_access_token realm_id = realm_id end end
Public Instance Methods
access_token=(token)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 41 def access_token=(token) @oauth = token end
enforce_filter_order(filters)
click to toggle source
Intuit API requires that filters obey a specific ordering Each Service
implementation should have a FILTER_ORDER
Array constant defined. If this is defined than any filters given will be re-ordered to match the required ordering
# File lib/quickeebooks/windows/service/service_base.rb, line 61 def enforce_filter_order(filters) if self.class.const_defined?(:FILTER_ORDER) self.class.const_get(:FILTER_ORDER).map do |field| filters.detect { |f| f.field.to_s == field } end.compact else filters end end
realm_id=(realm_id)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 45 def realm_id=(realm_id) @realm_id = realm_id end
url_for_base(raw)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 53 def url_for_base(raw) "#{@base_uri}/#{raw}/v2/#{@realm_id}" end
url_for_resource(resource)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 49 def url_for_resource(resource) url_for_base(resource) end
Private Instance Methods
add_query_string_to_url(url, params)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 201 def add_query_string_to_url(url, params) if params.is_a?(Hash) && !params.empty? url + "?" + params.collect { |k| "#{k.first}=#{k.last}" }.join("&") else url end end
check_response(response)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 209 def check_response(response) log "RESPONSE CODE = #{response.code}" log "RESPONSE BODY = #{response.body}" parse_xml(response.body) status = response.code.to_i case status when 200 # even HTTP 200 can contain an error, so we always have to peek for an Error if response_is_error? parse_and_raise_exception else response end when 302 raise "Unhandled HTTP Redirect" when 401 raise AuthorizationFailure when 400, 500 parse_and_raise_exception else raise "HTTP Error Code: #{status}, Msg: #{response.body}" end end
do_http(method, url, body, headers)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 185 def do_http(method, url, body, headers) # throws IntuitRequestException if @oauth.nil? raise "OAuth client has not been initialized. Initialize with setter access_token=" end unless headers.has_key?('Content-Type') headers.merge!({'Content-Type' => 'application/xml'}) end log "------ New Request ------" log "METHOD = #{method}" log "RESOURCE = #{url}" log "BODY(#{body.class}) = #{body == nil ? "<NIL>" : body.inspect}" log "HEADERS = #{headers.inspect}" response = @oauth.request(method, url, body, headers) check_response(response) end
do_http_get(url, params = {}, headers = {})
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 180 def do_http_get(url, params = {}, headers = {}) # throws IntuitRequestException url = add_query_string_to_url(url, params) do_http(:get, url, "", headers) end
do_http_post(url, body = "", params = {}, headers = {})
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 175 def do_http_post(url, body = "", params = {}, headers = {}) # throws IntuitRequestException url = add_query_string_to_url(url, params) do_http(:post, url, body, headers) end
fetch_collection(model, custom_field_query = nil, filters = [], page = 1, per_page = 20, sort = nil, options ={})
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 99 def fetch_collection(model, custom_field_query = nil, filters = [], page = 1, per_page = 20, sort = nil, options ={}) raise ArgumentError, "missing model to instantiate" if model.nil? post_body_tags = [] # pagination parameters must come first post_body_tags << "<StartPage>#{page}</StartPage>" post_body_tags << "<ChunkSize>#{per_page}</ChunkSize>" # ... followed by any filters if filters.is_a?(Array) && filters.length > 0 filters = enforce_filter_order(filters).compact post_body_tags << filters.collect { |f| f.to_xml } post_body_tags.flatten! end if sort post_body_tags << sort.to_xml end post_body_tags << custom_field_query xml_query_tag = "#{model::XML_NODE}Query" body = %Q{<?xml version="1.0" encoding="utf-8"?>\n<#{xml_query_tag} xmlns="http://www.intuit.com/sb/cdm/v2">#{post_body_tags.join}</#{xml_query_tag}>} response = do_http_post(url_for_resource(model::REST_RESOURCE), body, {}, {'Content-Type' => 'text/xml'}) parse_collection(response, model) end
fetch_object(model, url, params = {}, options = {})
click to toggle source
In QBD a single object response is the same as a collection response except it just has a single main element
# File lib/quickeebooks/windows/service/service_base.rb, line 88 def fetch_object(model, url, params = {}, options = {}) raise ArgumentError, "missing model to instantiate" if model.nil? response = do_http_get(url, params, {'Content-Type' => 'text/xml'}) collection = parse_collection(response, model) if collection.is_a?(Quickeebooks::Collection) collection.entries.first else nil end end
parse_and_raise_exception()
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 233 def parse_and_raise_exception err = parse_intuit_error ex = IntuitRequestException.new(err[:message]) ex.code = err[:code] ex.cause = err[:cause] raise ex end
parse_collection(response, model)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 128 def parse_collection(response, model) if response collection = Quickeebooks::Collection.new xml = @last_response_xml begin results = [] path_to_nodes = "//xmlns:RestResponse/xmlns:#{model::XML_COLLECTION_NODE}/xmlns:#{model::XML_NODE}" collection.count = xml.xpath(path_to_nodes).count if collection.count > 0 xml.xpath(path_to_nodes).each do |xa| entry = model.from_xml(xa) results << entry end end collection.entries = results collection.current_page = 1 # TODO: fix this rescue => ex #log("Error parsing XML: #{ex.message}") raise IntuitRequestException.new("Error parsing XML: #{ex.message}") end collection else nil end end
parse_intuit_error()
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 245 def parse_intuit_error error = {:message => "", :code => 0, :cause => ""} fault = @last_response_xml.xpath("//xmlns:RestResponse/xmlns:Error/xmlns:ErrorDesc")[0] if fault error[:message] = fault.text end error_code = @last_response_xml.xpath("//xmlns:RestResponse/xmlns:Error/xmlns:ErrorCode")[0] if error_code error[:code] = error_code.text end error end
parse_xml(xml)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 73 def parse_xml(xml) @last_response_xml = begin x = Nokogiri::XML(xml) #x.document.remove_namespaces! x end end
perform_write(model, body = "", params = {}, headers = {})
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 154 def perform_write(model, body = "", params = {}, headers = {}) url = url_for_resource(model::REST_RESOURCE) unless headers.has_key?('Content-Type') headers['Content-Type'] = 'text/xml' end response = do_http_post(url, body.strip, params, headers) result = nil if response case response.code.to_i when 200 result = Quickeebooks::Windows::Model::RestResponse.from_xml(response.body) when 401 raise IntuitRequestException.new("Authorization failure: token timed out?") when 404 raise IntuitRequestException.new("Resource Not Found: Check URL and try again") end end result end
response_is_error?()
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 241 def response_is_error? @last_response_xml.xpath("//xmlns:RestResponse/xmlns:Error").first != nil end
valid_xml_document(xml)
click to toggle source
# File lib/quickeebooks/windows/service/service_base.rb, line 82 def valid_xml_document(xml) %Q{<?xml version="1.0" encoding="utf-8"?>\n#{xml.strip}} end