Commit 96149efabcc7275d6e2ac7453a119b76dc57b976

Authored by Isaac Lewis
1 parent 0c0af54a

working query browse

1 PATH 1 PATH
2 remote: . 2 remote: .
3 specs: 3 specs:
4 - syspro (0.1.0) 4 + syspro-ruby (0.1.0)
5 faraday (~> 0.10) 5 faraday (~> 0.10)
6 6
7 GEM 7 GEM
@@ -26,7 +26,7 @@ DEPENDENCIES @@ -26,7 +26,7 @@ DEPENDENCIES
26 minitest (~> 5.0) 26 minitest (~> 5.0)
27 pry (~> 0.11) 27 pry (~> 0.11)
28 rake (~> 10.0) 28 rake (~> 10.0)
29 - syspro! 29 + syspro-ruby!
30 30
31 BUNDLED WITH 31 BUNDLED WITH
32 1.16.1 32 1.16.1
@@ -18,6 +18,11 @@ require "syspro/util" @@ -18,6 +18,11 @@ require "syspro/util"
18 require "syspro/version" 18 require "syspro/version"
19 19
20 require "syspro/api_operations/request" 20 require "syspro/api_operations/request"
  21 +require "syspro/api_operations/query"
  22 +
  23 +require "syspro/business_objects/combrw"
  24 +
  25 +require "syspro/business_objects/parsers/combrw_parser"
21 26
22 module Syspro 27 module Syspro
23 @api_base = "http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest" 28 @api_base = "http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest"
lib/syspro/api_operations/query.rb 0 → 100644
  1 +module Syspro
  2 + module ApiOperations
  3 + module Query
  4 + module ClassMethods
  5 + include Request
  6 +
  7 + def browse(params)
  8 + request(:get, "/Query/Browse", params)
  9 + end
  10 +
  11 + def fetch
  12 + end
  13 +
  14 + def query
  15 + end
  16 +
  17 + def find
  18 + end
  19 +
  20 + private
  21 +
  22 + def warn_on_opts_in_params(params)
  23 + Util::OPTS_USER_SPECIFIED.each do |opt|
  24 + if params.key?(opt)
  25 + $stderr.puts("WARNING: #{opt} should be in opts instead of params.")
  26 + end
  27 + end
  28 + end
  29 + end # ClassMethods
  30 +
  31 + def self.included(base)
  32 + base.extend(ClassMethods)
  33 + end
  34 +
  35 + protected
  36 +
  37 + def request(method, url, params = {}, opts = {})
  38 + opts = @opts.merge(Util.normalize_opts(opts))
  39 + Request.request(method, url, params, opts)
  40 + end
  41 + end
  42 + end
  43 +end
  44 +
lib/syspro/api_operations/request.rb
@@ -37,13 +37,6 @@ module Syspro @@ -37,13 +37,6 @@ module Syspro
37 def self.included(base) 37 def self.included(base)
38 base.extend(ClassMethods) 38 base.extend(ClassMethods)
39 end 39 end
40 -  
41 - protected  
42 -  
43 - def request(method, url, params = {}, opts = {})  
44 - opts = @opts.merge(Util.normalize_opts(opts))  
45 - self.class.request(method, url, params, opts)  
46 - end  
47 end 40 end
48 end 41 end
49 end 42 end
lib/syspro/business_objects/combrw.rb 0 → 100644
  1 +require "syspro/business_objects/parsers/combrw_parser"
  2 +require "erb"
  3 +
  4 +module Syspro
  5 + module BusinessObjects
  6 + class ComBrw < ApiResource
  7 + include Syspro::ApiOperations::Query
  8 + include Syspro::BusinessObjects::Parsers
  9 +
  10 + attr_accessor :browse_name, :start_condition, :return_rows, :filters,
  11 + :table_name, :title, :columns
  12 +
  13 + def call(user_id)
  14 + xml_in = template.result(binding)
  15 + params = { "UserId" => user_id, "XmlIn" => xml_in }
  16 + resp = ComBrw.browse(params)
  17 + parse_response(resp)
  18 + end
  19 +
  20 + def template
  21 + ERB.new File.read(File.expand_path("schemas/combrw.xml.erb", File.dirname(__FILE__))), nil, "%"
  22 + end
  23 +
  24 + def parse_response(resp)
  25 + handle_errors(resp)
  26 + ComBrwParser.parse(resp[0].data)
  27 + end
  28 +
  29 + def handle_errors(resp)
  30 + body = resp[0].http_body
  31 + if body.match(/^(ERROR)/)
  32 + raise SysproError, body
  33 + end
  34 + end
  35 + end
  36 + end
  37 +end
  38 +
lib/syspro/business_objects/parsers/combrw_parser.rb 0 → 100644
  1 +module Syspro
  2 + module BusinessObjects
  3 + module Parsers
  4 + class ComBrwParser
  5 +
  6 + def self.parse(doc)
  7 + next_prev_key = doc.first_element_child.xpath("NextPrevKey")
  8 + next_prev_key_obj = next_prev_key.children.map { |el|
  9 + if el.name == "text"
  10 + next
  11 + end
  12 + {
  13 + name: el.name,
  14 + text: el.text
  15 + }
  16 + }.compact
  17 +
  18 + header_details = doc.first_element_child.xpath("HeaderDetails")
  19 + header_details_obj = header_details.children.map { |el|
  20 + if el.name == "text"
  21 + next
  22 + end
  23 + {
  24 + name: el.name,
  25 + text: el.text
  26 + }
  27 + }.compact
  28 +
  29 + rows = doc.first_element_child.xpath('Row')
  30 + rows_obj = rows.map { |el|
  31 + el.elements.map { |el|
  32 + {
  33 + name: el.name,
  34 + value: el.xpath('Value').text,
  35 + data_type: el.xpath('DataType').text
  36 + }
  37 + }
  38 + }.flatten(1).compact
  39 +
  40 + BrowseObject.new(
  41 + doc.first_element_child.xpath("Title").text,
  42 + rows_obj,
  43 + next_prev_key_obj,
  44 + header_details_obj
  45 + )
  46 + end
  47 +
  48 + BrowseObject = Struct.new(:title, :rows, :next_prev_key, :header_details)
  49 + end
  50 + end
  51 + end
  52 +end
  53 +
lib/syspro/business_objects/schemas/combrw.xml.erb 0 → 100644
  1 +<?xml version="1.0" encoding="Windows-1252"?>
  2 +<!-- Copyright 1994-2014 SYSPRO Ltd.-->
  3 +<!--
  4 + Sample XML for the Generic Browse Object
  5 +-->
  6 +<Browse xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:noNamespaceSchemaLocation="COMBRW.XSD">
  7 + <BrowseName><%= @browse_name %></BrowseName>
  8 + <StartAtKey/>
  9 + <StartCondition><%= @start_condition %></StartCondition>
  10 + <ReturnRows><%= @return_rows %></ReturnRows>
  11 + <% for @filter in @filters %>
  12 + <Filter>
  13 + <ColumnFilterName><%= @filter[:name] %></ColumnFilterName>
  14 + <ColumnFilterValue><%= @filter[:value] %></ColumnFilterValue>
  15 + </Filter>
  16 + <% end %>
  17 + <BrowseDetails>
  18 + <TableName><%= @table_name %></TableName>
  19 + <Title><%= @title %></Title>
  20 + <% for @column in @columns %>
  21 + <Column>
  22 + <% unless @column[:name].nil? %><ColumnName><%= @column[:name] %></ColumnName><% end %>
  23 + <% unless @column[:description].nil? %><ColumnDescription><%= @column[:description] %></ColumnDescription><% end %>
  24 + <% unless @column[:key].nil? %><ColumnKey><%= @column[:key] %></ColumnKey><% end %>
  25 + </Column>
  26 + <% end %>
  27 + </BrowseDetails>
  28 +</Browse>
  29 +
lib/syspro/syspro_client.rb
@@ -178,9 +178,9 @@ module Syspro @@ -178,9 +178,9 @@ module Syspro
178 case e 178 case e
179 when Faraday::ClientError 179 when Faraday::ClientError
180 if e.response 180 if e.response
181 - handle_error_response(e.response, error_context) 181 + handle_error_response(e.response, context)
182 else 182 else
183 - handle_network_error(e, error_context, num_retries, api_base) 183 + handle_network_error(e, context, num_retries, api_base)
184 end 184 end
185 185
186 # Only handle errors when we know we can do so, and re-raise otherwise. 186 # Only handle errors when we know we can do so, and re-raise otherwise.
@@ -193,6 +193,35 @@ module Syspro @@ -193,6 +193,35 @@ module Syspro
193 resp 193 resp
194 end 194 end
195 195
  196 + def handle_network_error(e, context, num_retries, api_base = nil)
  197 + Util.log_error("Syspro network error",
  198 + error_message: e.message,
  199 + request_id: context.request_id)
  200 +
  201 + case e
  202 + when Faraday::ConnectionFailed
  203 + message = "Unexpected error communicating when trying to connect to Syspro."
  204 +
  205 + when Faraday::SSLError
  206 + message = "Could not establish a secure connection to Syspro."
  207 +
  208 + when Faraday::TimeoutError
  209 + api_base ||= Syspro.api_base
  210 + message = "Could not connect to Syspro (#{api_base}). " \
  211 + "Please check your internet connection and try again. " \
  212 + "If this problem persists, you should check your Syspro service status."
  213 +
  214 + else
  215 + message = "Unexpected error communicating with Syspro. " \
  216 + "If this problem persists, talk to your Syspro implementation team."
  217 +
  218 + end
  219 +
  220 + message += " Request was retried #{num_retries} times." if num_retries > 0
  221 +
  222 + raise ApiConnectionError, message + "\n\n(Network error: #{e.message})"
  223 + end
  224 +
196 def self.should_retry?(e, num_retries) 225 def self.should_retry?(e, num_retries)
197 return false if num_retries >= Syspro.max_network_retries 226 return false if num_retries >= Syspro.max_network_retries
198 227
@@ -249,6 +278,26 @@ module Syspro @@ -249,6 +278,26 @@ module Syspro
249 end 278 end
250 private :log_response_error 279 private :log_response_error
251 280
  281 + def handle_error_response(http_resp, context)
  282 + begin
  283 + resp = SysproResponse.from_faraday_hash(http_resp)
  284 + error_data = resp.data[:error]
  285 +
  286 + raise SysproError, "Indeterminate error" unless error_data
  287 + rescue Nokogiri::XML::SyntaxError, SysproError
  288 + raise general_api_error(http_resp[:status], http_resp[:body])
  289 + end
  290 +
  291 + error = if error_data.is_a?(String)
  292 + specific_oauth_error(resp, error_data, context)
  293 + else
  294 + specific_api_error(resp, error_data, context)
  295 + end
  296 +
  297 + error.response = resp
  298 + raise(error)
  299 + end
  300 +
252 # RequestLogContext stores information about a request that's begin made so 301 # RequestLogContext stores information about a request that's begin made so
253 # that we can log certain information. It's useful because it means that we 302 # that we can log certain information. It's useful because it means that we
254 # don't have to pass around as many parameters. 303 # don't have to pass around as many parameters.
test/query_test.rb 0 → 100644
  1 +require "test_helper"
  2 +
  3 +class QueryTest < Minitest::Test
  4 + def test_query
  5 + user_id = Syspro::Logon.logon("wland", "piperita2016", "L", "")
  6 +
  7 + combrw = Syspro::BusinessObjects::ComBrw.new
  8 + combrw.browse_name = "InvMaster"
  9 + combrw.start_condition = ""
  10 + combrw.return_rows = 5
  11 + combrw.filters = []
  12 + combrw.table_name = "InvMaster"
  13 + combrw.title = "StockCodes"
  14 + combrw.columns = [
  15 + {name: "StockCode"}
  16 + ]
  17 +
  18 + query_result = combrw.call(user_id.guid)
  19 +
  20 + refute_nil query_result
  21 + end
  22 +end