Commit 291179ed2e407c287e1359c1add0a9900164fa69
Committed by
GitHub
Merge pull request #2 from wildland/query
Query Endpoint
Showing
46 changed files
with
1499 additions
and
255 deletions
Show diff stats
1 | +# Changelog | ||
2 | +All notable changes to this project will be documented in this file. | ||
3 | + | ||
4 | +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) | ||
5 | +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). | ||
6 | + | ||
7 | +## [Unreleased] | ||
8 | +### Added | ||
9 | +### Changed | ||
10 | +### Deprecated | ||
11 | +### Removed | ||
12 | +### Fixed | ||
13 | +### Security | ||
14 | + | ||
15 | +## 0.1.0 - 2018-04-06 | ||
16 | +### Added | ||
17 | +- CHANGELOG file | ||
18 | +- `rubocop` gem | ||
19 | +- `vcr` gem | ||
20 | +- Query Endpoint |
Gemfile
Gemfile.lock
1 | PATH | 1 | PATH |
2 | remote: . | 2 | remote: . |
3 | specs: | 3 | specs: |
4 | - syspro (0.1.0) | 4 | + syspro-ruby (1.0.0.alpha.1) |
5 | faraday (~> 0.10) | 5 | faraday (~> 0.10) |
6 | + nokogiri (~> 1.8.2) | ||
6 | 7 | ||
7 | GEM | 8 | GEM |
8 | remote: https://rubygems.org/ | 9 | remote: https://rubygems.org/ |
9 | specs: | 10 | specs: |
11 | + addressable (2.5.2) | ||
12 | + public_suffix (>= 2.0.2, < 4.0) | ||
13 | + ast (2.4.0) | ||
10 | coderay (1.1.2) | 14 | coderay (1.1.2) |
15 | + crack (0.4.3) | ||
16 | + safe_yaml (~> 1.0.0) | ||
11 | faraday (0.14.0) | 17 | faraday (0.14.0) |
12 | multipart-post (>= 1.2, < 3) | 18 | multipart-post (>= 1.2, < 3) |
19 | + hashdiff (0.3.7) | ||
13 | method_source (0.9.0) | 20 | method_source (0.9.0) |
21 | + mini_portile2 (2.3.0) | ||
22 | + minispec-metadata (2.0.0) | ||
23 | + minitest | ||
14 | minitest (5.11.3) | 24 | minitest (5.11.3) |
25 | + minitest-vcr (1.4.0) | ||
26 | + minispec-metadata (~> 2.0) | ||
27 | + minitest (>= 4.7.5) | ||
28 | + vcr (>= 2.9) | ||
15 | multipart-post (2.0.0) | 29 | multipart-post (2.0.0) |
30 | + nokogiri (1.8.2) | ||
31 | + mini_portile2 (~> 2.3.0) | ||
32 | + parallel (1.12.1) | ||
33 | + parser (2.5.0.5) | ||
34 | + ast (~> 2.4.0) | ||
35 | + powerpack (0.1.1) | ||
16 | pry (0.11.3) | 36 | pry (0.11.3) |
17 | coderay (~> 1.1.0) | 37 | coderay (~> 1.1.0) |
18 | method_source (~> 0.9.0) | 38 | method_source (~> 0.9.0) |
39 | + public_suffix (3.0.2) | ||
40 | + rainbow (3.0.0) | ||
19 | rake (10.5.0) | 41 | rake (10.5.0) |
42 | + rubocop (0.54.0) | ||
43 | + parallel (~> 1.10) | ||
44 | + parser (>= 2.5) | ||
45 | + powerpack (~> 0.1) | ||
46 | + rainbow (>= 2.2.2, < 4.0) | ||
47 | + ruby-progressbar (~> 1.7) | ||
48 | + unicode-display_width (~> 1.0, >= 1.0.1) | ||
49 | + ruby-progressbar (1.9.0) | ||
50 | + safe_yaml (1.0.4) | ||
51 | + unicode-display_width (1.3.0) | ||
52 | + vcr (4.0.0) | ||
53 | + webmock (3.3.0) | ||
54 | + addressable (>= 2.3.6) | ||
55 | + crack (>= 0.3.2) | ||
56 | + hashdiff | ||
20 | 57 | ||
21 | PLATFORMS | 58 | PLATFORMS |
22 | ruby | 59 | ruby |
@@ -24,9 +61,12 @@ PLATFORMS | @@ -24,9 +61,12 @@ PLATFORMS | ||
24 | DEPENDENCIES | 61 | DEPENDENCIES |
25 | bundler (~> 1.16) | 62 | bundler (~> 1.16) |
26 | minitest (~> 5.0) | 63 | minitest (~> 5.0) |
64 | + minitest-vcr (~> 1.4.0) | ||
27 | pry (~> 0.11) | 65 | pry (~> 0.11) |
28 | rake (~> 10.0) | 66 | rake (~> 10.0) |
29 | - syspro! | 67 | + rubocop (~> 0.54.0) |
68 | + syspro-ruby! | ||
69 | + webmock (~> 3.3.0) | ||
30 | 70 | ||
31 | BUNDLED WITH | 71 | BUNDLED WITH |
32 | 1.16.1 | 72 | 1.16.1 |
README.md
@@ -72,6 +72,103 @@ logged_off = Syspro::Logoff.logoff(guid) | @@ -72,6 +72,103 @@ logged_off = Syspro::Logoff.logoff(guid) | ||
72 | ``` | 72 | ``` |
73 | `logged_off` will be `true` if the user has been successfully logged off, and will contain an error string if an error has occured. | 73 | `logged_off` will be `true` if the user has been successfully logged off, and will contain an error string if an error has occured. |
74 | 74 | ||
75 | +### Query | ||
76 | + | ||
77 | +#### Browse | ||
78 | +Browse returns a paginated view of a particular table. | ||
79 | + | ||
80 | +This is an example using the generic Browse Business Object, `COMBRW`. | ||
81 | +```rb | ||
82 | +combrw = Syspro::BusinessObject::ComBrw.new | ||
83 | +combrw.browse_name = "InvMaster" | ||
84 | +combrw.start_condition = "" | ||
85 | +combrw.return_rows = 5 | ||
86 | +combrw.filters = [] | ||
87 | +combrw.table_name = "InvMaster" | ||
88 | +combrw.title = "StockCodes" | ||
89 | +combrw.columns = [ | ||
90 | + {name: "StockCode"} | ||
91 | +] | ||
92 | + | ||
93 | +browse_result = combrw.call(user_id.guid) | ||
94 | +``` | ||
95 | + | ||
96 | +`browse_result` will be a BrowseObject, which has the following structure: | ||
97 | + | ||
98 | +```rb | ||
99 | +{ | ||
100 | + title: "Title", | ||
101 | + rows: [ { name: "", value: "", data_type: "" } ], | ||
102 | + next_prev_key: { name: "", text: "" }, | ||
103 | + header_details: { name: "", text: "" } | ||
104 | +} | ||
105 | +``` | ||
106 | + | ||
107 | +#### Query | ||
108 | + | ||
109 | +Query gives control over joins between multiple tables over a single Business Object. | ||
110 | + | ||
111 | +This is an example using the generic Query Business Object, `COMFND`. | ||
112 | + | ||
113 | +```rb | ||
114 | +comfnd = Syspro::BusinessObjects::ComFnd.new | ||
115 | +comfnd.table_name = "InvMaster" | ||
116 | +comfnd.return_rows = 5 | ||
117 | +comfnd.columns = [ | ||
118 | + { | ||
119 | + name: "StockCode" | ||
120 | + } | ||
121 | +] | ||
122 | +comfnd.expressions = [ | ||
123 | + { | ||
124 | + andor: "And", | ||
125 | + column: "StockCode", | ||
126 | + condition: "EQ", | ||
127 | + value: "02" | ||
128 | + } | ||
129 | +] | ||
130 | +comfnd.order_by = "StockCode" | ||
131 | + | ||
132 | +query_result = comfnd.call(user_id.guid) | ||
133 | +``` | ||
134 | + | ||
135 | +This will return a QueryObject, which looks like this: | ||
136 | + | ||
137 | +```rb | ||
138 | +{ | ||
139 | + header_details: { name: "", text: "" }, | ||
140 | + rows: [ { name: "", value: "" } ], | ||
141 | + row_count: 1 | ||
142 | +} | ||
143 | +``` | ||
144 | + | ||
145 | +#### Fetch | ||
146 | + | ||
147 | +Fetch selects the `TOP 1` of the query. | ||
148 | + | ||
149 | +This is an example using the generic Fetch Business Object, `COMFCH`. | ||
150 | + | ||
151 | +```rb | ||
152 | +comfch = Syspro::BusinessObjects::ComFch.new | ||
153 | +comfch.table_name = "InvMaster" | ||
154 | +comfch.key = "02" | ||
155 | +comfch.optional_keys = [] | ||
156 | +comfch.full_key_provided = false | ||
157 | +comfch.default_type = "" | ||
158 | +comfch.espresso_fetch = true | ||
159 | + | ||
160 | +fetch_result = comfch.call(user_id.guid) | ||
161 | +``` | ||
162 | + | ||
163 | +This will return a FetchObject, with the following structure: | ||
164 | + | ||
165 | +```rb | ||
166 | +{ | ||
167 | + table_name: "", | ||
168 | + columns: [ { name: "", value: "" } ] | ||
169 | +} | ||
170 | +``` | ||
171 | + | ||
75 | ## Development | 172 | ## Development |
76 | 173 | ||
77 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. | 174 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. |
@@ -80,6 +177,8 @@ To install this gem onto your local machine, run `bundle exec rake install`. To | @@ -80,6 +177,8 @@ To install this gem onto your local machine, run `bundle exec rake install`. To | ||
80 | 177 | ||
81 | ## Contributing | 178 | ## Contributing |
82 | 179 | ||
180 | +Run `bundle exec rake` and ensure everything looks good. | ||
181 | + | ||
83 | Bug reports and pull requests are welcome on GitHub at https://github.com/ike/syspro-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. | 182 | Bug reports and pull requests are welcome on GitHub at https://github.com/ike/syspro-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. |
84 | 183 | ||
85 | ## License | 184 | ## License |
@@ -88,4 +187,4 @@ The gem is available as open source under the terms of the [MIT License](https:/ | @@ -88,4 +187,4 @@ The gem is available as open source under the terms of the [MIT License](https:/ | ||
88 | 187 | ||
89 | ## Code of Conduct | 188 | ## Code of Conduct |
90 | 189 | ||
91 | -Everyone interacting in the Syspro project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ike/syspro-ruby/blob/master/CODE_OF_CONDUCT.md). | 190 | +Everyone interacting in the Syspro project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/wildland/code-of-conduct). |
Rakefile
1 | -require "bundler/gem_tasks" | ||
2 | -require "rake/testtask" | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +require 'bundler/gem_tasks' | ||
4 | +require 'rake/testtask' | ||
5 | +require 'rubocop/rake_task' | ||
3 | 6 | ||
4 | Rake::TestTask.new(:test) do |t| | 7 | Rake::TestTask.new(:test) do |t| |
5 | - t.libs << "test" | ||
6 | - t.libs << "lib" | ||
7 | - t.test_files = FileList["test/**/*_test.rb"] | 8 | + t.libs << 'test' |
9 | + t.libs << 'lib' | ||
10 | + t.test_files = FileList['test/**/*_test.rb'] | ||
8 | end | 11 | end |
9 | 12 | ||
10 | -task :default => :test | 13 | +task default: %i[test rubocop] |
14 | + | ||
15 | +RuboCop::RakeTask.new(:rubocop) do |t| | ||
16 | + t.options = ['--display-cop-names'] | ||
17 | +end |
bin/console
lib/syspro.rb
1 | -require "cgi" | ||
2 | -require "faraday" | ||
3 | -require "json" | ||
4 | -require "logger" | ||
5 | -require "openssl" | ||
6 | - | ||
7 | -require "syspro/api_resource" | ||
8 | -require "syspro/errors" | ||
9 | -require "syspro/get_logon_profile" | ||
10 | -require "syspro/get_version" | ||
11 | -require "syspro/logoff" | ||
12 | -require "syspro/logon" | ||
13 | -require "syspro/syspro_client" | ||
14 | -require "syspro/singleton_api_resource" | ||
15 | -require "syspro/syspro_object" | ||
16 | -require "syspro/syspro_response" | ||
17 | -require "syspro/util" | ||
18 | -require "syspro/version" | ||
19 | - | ||
20 | -require "syspro/api_operations/request" | ||
21 | - | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +require 'cgi' | ||
4 | +require 'faraday' | ||
5 | +require 'json' | ||
6 | +require 'logger' | ||
7 | +require 'openssl' | ||
8 | + | ||
9 | +require 'syspro/api_resource' | ||
10 | +require 'syspro/errors' | ||
11 | +require 'syspro/get_logon_profile' | ||
12 | +require 'syspro/get_version' | ||
13 | +require 'syspro/logoff' | ||
14 | +require 'syspro/logon' | ||
15 | +require 'syspro/syspro_client' | ||
16 | +require 'syspro/singleton_api_resource' | ||
17 | +require 'syspro/syspro_object' | ||
18 | +require 'syspro/syspro_response' | ||
19 | +require 'syspro/util' | ||
20 | +require 'syspro/version' | ||
21 | + | ||
22 | +require 'syspro/api_operations/request' | ||
23 | +require 'syspro/api_operations/query' | ||
24 | + | ||
25 | +require 'syspro/business_objects/combrw' | ||
26 | +require 'syspro/business_objects/comfch' | ||
27 | +require 'syspro/business_objects/comfnd' | ||
28 | + | ||
29 | +require 'syspro/business_objects/parsers/combrw_parser' | ||
30 | +require 'syspro/business_objects/parsers/comfch_parser' | ||
31 | +require 'syspro/business_objects/parsers/comfnd_parser' | ||
32 | + | ||
33 | +# Main Module | ||
22 | module Syspro | 34 | module Syspro |
23 | - @api_base = "http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest" | 35 | + @api_base = 'http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest' |
24 | 36 | ||
25 | @open_timeout = 30 | 37 | @open_timeout = 30 |
26 | @read_timeout = 80 | 38 | @read_timeout = 80 |
@@ -60,14 +72,13 @@ module Syspro | @@ -60,14 +72,13 @@ module Syspro | ||
60 | 72 | ||
61 | def self.log_level=(val) | 73 | def self.log_level=(val) |
62 | # Backwards compatibility for values that we briefly allowed | 74 | # Backwards compatibility for values that we briefly allowed |
63 | - if val == "debug" | ||
64 | - val = LEVEL_DEBUG | ||
65 | - elsif val == "info" | ||
66 | - val = LEVEL_INFO | ||
67 | - end | ||
68 | - | 75 | + val = LEVEL_DEBUG if val == 'debug' |
76 | + val = LEVEL_INFO if val == 'info' | ||
69 | if !val.nil? && ![LEVEL_DEBUG, LEVEL_ERROR, LEVEL_INFO].include?(val) | 77 | if !val.nil? && ![LEVEL_DEBUG, LEVEL_ERROR, LEVEL_INFO].include?(val) |
70 | - raise ArgumentError, "log_level should only be set to `nil`, `debug` or `info`" | 78 | + raise( |
79 | + ArgumentError, | ||
80 | + 'log_level should only be set to `nil`, `debug` or `info`' | ||
81 | + ) | ||
71 | end | 82 | end |
72 | @log_level = val | 83 | @log_level = val |
73 | end | 84 | end |
@@ -95,5 +106,5 @@ module Syspro | @@ -95,5 +106,5 @@ module Syspro | ||
95 | @max_network_retries = val.to_i | 106 | @max_network_retries = val.to_i |
96 | end | 107 | end |
97 | 108 | ||
98 | - Syspro.log_level = ENV["SYSPRO_LOG"] unless ENV["SYSPRO_LOG"].nil? | 109 | + Syspro.log_level = ENV['SYSPRO_LOG'] unless ENV['SYSPRO_LOG'].nil? |
99 | end | 110 | end |
1 | +# frozen_string_literal: true | ||
2 | + | ||
3 | +module Syspro | ||
4 | + module ApiOperations | ||
5 | + module Query | ||
6 | + module ClassMethods | ||
7 | + def browse(params) | ||
8 | + request(:get, '/Query/Browse', params) | ||
9 | + end | ||
10 | + | ||
11 | + def fetch(params) | ||
12 | + request(:get, '/Query/Fetch', params) | ||
13 | + end | ||
14 | + | ||
15 | + def query(params) | ||
16 | + request(:get, '/Query/Query', params) | ||
17 | + end | ||
18 | + | ||
19 | + def find; end | ||
20 | + | ||
21 | + private | ||
22 | + | ||
23 | + def warn_on_opts_in_params(params) | ||
24 | + Util::OPTS_USER_SPECIFIED.each do |opt| | ||
25 | + if params.key?(opt) | ||
26 | + warn("WARNING: #{opt} should be in opts instead of params.") | ||
27 | + end | ||
28 | + end | ||
29 | + end | ||
30 | + end # ClassMethods | ||
31 | + | ||
32 | + def self.included(base) | ||
33 | + base.extend(ClassMethods) | ||
34 | + end | ||
35 | + | ||
36 | + protected | ||
37 | + | ||
38 | + def request(method, url, params = {}, opts = {}) | ||
39 | + opts = @opts.merge(Util.normalize_opts(opts)) | ||
40 | + Request.request(method, url, params, opts) | ||
41 | + end | ||
42 | + end | ||
43 | + end | ||
44 | +end |
lib/syspro/api_operations/request.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
2 | module ApiOperations | 4 | module ApiOperations |
3 | module Request | 5 | module Request |
@@ -28,7 +30,7 @@ module Syspro | @@ -28,7 +30,7 @@ module Syspro | ||
28 | def warn_on_opts_in_params(params) | 30 | def warn_on_opts_in_params(params) |
29 | Util::OPTS_USER_SPECIFIED.each do |opt| | 31 | Util::OPTS_USER_SPECIFIED.each do |opt| |
30 | if params.key?(opt) | 32 | if params.key?(opt) |
31 | - $stderr.puts("WARNING: #{opt} should be in opts instead of params.") | 33 | + warn("WARNING: #{opt} should be in opts instead of params.") |
32 | end | 34 | end |
33 | end | 35 | end |
34 | end | 36 | end |
@@ -37,14 +39,6 @@ module Syspro | @@ -37,14 +39,6 @@ module Syspro | ||
37 | def self.included(base) | 39 | def self.included(base) |
38 | base.extend(ClassMethods) | 40 | base.extend(ClassMethods) |
39 | end | 41 | 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 | 42 | end |
48 | end | 43 | end |
49 | end | 44 | end |
50 | - |
lib/syspro/api_resource.rb
1 | -require "syspro/syspro_object" | ||
2 | -require "syspro/api_operations/request" | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +require 'syspro/syspro_object' | ||
4 | +require 'syspro/api_operations/request' | ||
3 | 5 | ||
4 | module Syspro | 6 | module Syspro |
5 | class ApiResource < SysproObject | 7 | class ApiResource < SysproObject |
6 | include Syspro::ApiOperations::Request | 8 | include Syspro::ApiOperations::Request |
7 | 9 | ||
8 | def self.class_name | 10 | def self.class_name |
9 | - name.split("::")[-1] | 11 | + name.split('::')[-1] |
10 | end | 12 | end |
11 | 13 | ||
12 | def self.resource_url | 14 | def self.resource_url |
13 | if self == ApiResource | 15 | if self == ApiResource |
14 | - raise NotImplementedError, "APIResource is an abstract class. You should perform actions on its subclasses (Charge, Customer, etc.)" | 16 | + raise NotImplementedError, 'APIResource is an abstract class. You should perform actions on its subclasses (Charge, Customer, etc.)' |
15 | end | 17 | end |
16 | "/#{CGI.escape(class_name.downcase)}" | 18 | "/#{CGI.escape(class_name.downcase)}" |
17 | end | 19 | end |
1 | +# frozen_string_literal: true | ||
2 | + | ||
3 | +require 'syspro/business_objects/parsers/combrw_parser' | ||
4 | +require 'erb' | ||
5 | + | ||
6 | +module Syspro | ||
7 | + module BusinessObjects | ||
8 | + class ComBrw < ApiResource | ||
9 | + include Syspro::ApiOperations::Query | ||
10 | + include Syspro::BusinessObjects::Parsers | ||
11 | + | ||
12 | + attr_accessor :browse_name, :start_condition, :return_rows, :filters, | ||
13 | + :table_name, :title, :columns | ||
14 | + | ||
15 | + def call(user_id) | ||
16 | + xml_in = template.result(binding) | ||
17 | + params = { 'UserId' => user_id, 'XmlIn' => xml_in } | ||
18 | + resp = ComBrw.browse(params) | ||
19 | + parse_response(resp) | ||
20 | + end | ||
21 | + | ||
22 | + def template | ||
23 | + ERB.new( | ||
24 | + File.read( | ||
25 | + File.expand_path('schemas/combrw.xml.erb', File.dirname(__FILE__)) | ||
26 | + ), | ||
27 | + nil, | ||
28 | + '%' | ||
29 | + ) | ||
30 | + end | ||
31 | + | ||
32 | + def parse_response(resp) | ||
33 | + handle_errors(resp) | ||
34 | + parser = ComBrwParser.new(resp[0].data) | ||
35 | + parser.parse | ||
36 | + end | ||
37 | + | ||
38 | + def handle_errors(resp) | ||
39 | + body = resp[0].http_body | ||
40 | + raise SysproError, body if body =~ /^(ERROR)/ | ||
41 | + end | ||
42 | + end | ||
43 | + end | ||
44 | +end |
1 | +# frozen_string_literal: true | ||
2 | + | ||
3 | +require 'syspro/business_objects/parsers/comfch_parser' | ||
4 | +require 'erb' | ||
5 | + | ||
6 | +module Syspro | ||
7 | + module BusinessObjects | ||
8 | + class ComFch < ApiResource | ||
9 | + include Syspro::ApiOperations::Query | ||
10 | + include Syspro::BusinessObjects::Parsers | ||
11 | + | ||
12 | + attr_accessor :table_name, :key, :optional_keys, :full_key_provided, | ||
13 | + :default_type, :espresso_fetch | ||
14 | + | ||
15 | + def call(user_id) | ||
16 | + xml_in = template.result(binding) | ||
17 | + params = { 'UserId' => user_id, 'XmlIn' => xml_in } | ||
18 | + resp = ComFch.fetch(params) | ||
19 | + parse_response(resp) | ||
20 | + end | ||
21 | + | ||
22 | + def template | ||
23 | + ERB.new( | ||
24 | + File.read( | ||
25 | + File.expand_path('schemas/comfch.xml.erb', File.dirname(__FILE__)) | ||
26 | + ), | ||
27 | + nil, | ||
28 | + '%' | ||
29 | + ) | ||
30 | + end | ||
31 | + | ||
32 | + def parse_response(resp) | ||
33 | + handle_errors(resp) | ||
34 | + parser = ComFchParser.new(resp[0].data) | ||
35 | + parser.parse | ||
36 | + end | ||
37 | + | ||
38 | + def handle_errors(resp) | ||
39 | + body = resp[0].http_body | ||
40 | + raise SysproError, body if body =~ /^(ERROR)/ | ||
41 | + end | ||
42 | + end | ||
43 | + end | ||
44 | +end |
1 | +# frozen_string_literal: true | ||
2 | + | ||
3 | +require 'syspro/business_objects/parsers/comfnd_parser' | ||
4 | +require 'erb' | ||
5 | + | ||
6 | +module Syspro | ||
7 | + module BusinessObjects | ||
8 | + class ComFnd < ApiResource | ||
9 | + include Syspro::ApiOperations::Query | ||
10 | + include Syspro::BusinessObjects::Parsers | ||
11 | + | ||
12 | + attr_accessor :table_name, :return_rows, :columns, :expressions, | ||
13 | + :order_by | ||
14 | + | ||
15 | + def call(user_id) | ||
16 | + xml_in = template.result(binding) | ||
17 | + business_object = 'COMFND' | ||
18 | + params = { 'UserId' => user_id, 'BusinessObject' => business_object, 'XmlIn' => xml_in } | ||
19 | + resp = ComFnd.query(params) | ||
20 | + parse_response(resp) | ||
21 | + end | ||
22 | + | ||
23 | + def template | ||
24 | + ERB.new File.read(File.expand_path('schemas/comfnd.xml.erb', File.dirname(__FILE__))), nil, '%' | ||
25 | + end | ||
26 | + | ||
27 | + def parse_response(resp) | ||
28 | + handle_errors(resp) | ||
29 | + parser = ComFndParser.new(resp[0].data) | ||
30 | + parser.parse | ||
31 | + end | ||
32 | + | ||
33 | + def handle_errors(resp) | ||
34 | + body = resp[0].http_body | ||
35 | + raise SysproError, body if body =~ /^(ERROR)/ | ||
36 | + end | ||
37 | + end | ||
38 | + end | ||
39 | +end |
lib/syspro/business_objects/parsers/combrw_parser.rb
0 → 100644
1 | +# frozen_string_literal: true | ||
2 | + | ||
3 | +module Syspro | ||
4 | + module BusinessObjects | ||
5 | + module Parsers | ||
6 | + class ComBrwParser | ||
7 | + attr_reader :doc | ||
8 | + | ||
9 | + def initialize(doc) | ||
10 | + @doc = doc | ||
11 | + end | ||
12 | + | ||
13 | + def parse | ||
14 | + next_prev_key = doc.first_element_child.xpath('NextPrevKey') | ||
15 | + next_prev_key_obj = next_prev_key.children.map do |el| | ||
16 | + next if el.name == 'text' | ||
17 | + { | ||
18 | + name: el.name, | ||
19 | + text: el.text | ||
20 | + } | ||
21 | + end.compact | ||
22 | + | ||
23 | + header_details = doc.first_element_child.xpath('HeaderDetails') | ||
24 | + header_details_obj = header_details.children.map do |el| | ||
25 | + next if el.name == 'text' | ||
26 | + { | ||
27 | + name: el.name, | ||
28 | + text: el.text | ||
29 | + } | ||
30 | + end.compact | ||
31 | + | ||
32 | + rows = doc.first_element_child.xpath('Row') | ||
33 | + rows_obj = rows.flat_map do |el| | ||
34 | + el.elements.map do |inner| | ||
35 | + { | ||
36 | + name: inner.name, | ||
37 | + value: inner.xpath('Value').text, | ||
38 | + data_type: inner.xpath('DataType').text | ||
39 | + } | ||
40 | + end | ||
41 | + end.compact | ||
42 | + | ||
43 | + BrowseObject.new( | ||
44 | + doc.first_element_child.xpath('Title').text, | ||
45 | + rows_obj, | ||
46 | + next_prev_key_obj, | ||
47 | + header_details_obj | ||
48 | + ) | ||
49 | + end | ||
50 | + | ||
51 | + BrowseObject = Struct.new(:title, :rows, :next_prev_key, :header_details) | ||
52 | + end | ||
53 | + end | ||
54 | + end | ||
55 | +end |
lib/syspro/business_objects/parsers/comfch_parser.rb
0 → 100644
1 | +# frozen_string_literal: true | ||
2 | + | ||
3 | +module Syspro | ||
4 | + module BusinessObjects | ||
5 | + module Parsers | ||
6 | + class ComFchParser | ||
7 | + attr_reader :doc | ||
8 | + | ||
9 | + def initialize(doc) | ||
10 | + @doc = doc | ||
11 | + end | ||
12 | + | ||
13 | + def parse | ||
14 | + table_name = doc.first_element_child.name | ||
15 | + columns = doc.first_element_child.elements | ||
16 | + columns_obj = columns.map do |el| | ||
17 | + { name: el.name, value: el.children.text } | ||
18 | + end.compact | ||
19 | + | ||
20 | + FetchObject.new( | ||
21 | + table_name, | ||
22 | + columns_obj | ||
23 | + ) | ||
24 | + end | ||
25 | + | ||
26 | + FetchObject = Struct.new(:table_name, :columns) | ||
27 | + end | ||
28 | + end | ||
29 | + end | ||
30 | +end |
lib/syspro/business_objects/parsers/comfnd_parser.rb
0 → 100644
1 | +# frozen_string_literal: true | ||
2 | + | ||
3 | +module Syspro | ||
4 | + module BusinessObjects | ||
5 | + module Parsers | ||
6 | + class ComFndParser | ||
7 | + attr_reader :doc | ||
8 | + | ||
9 | + def initialize(doc) | ||
10 | + @doc = doc | ||
11 | + end | ||
12 | + | ||
13 | + def parse | ||
14 | + header_details = doc.first_element_child.xpath('HeaderDetails') | ||
15 | + header_details_obj = header_details.children.map do |el| | ||
16 | + next if el.name == 'text' | ||
17 | + { | ||
18 | + name: el.name, | ||
19 | + text: el.text | ||
20 | + } | ||
21 | + end.compact | ||
22 | + | ||
23 | + rows = doc.first_element_child.xpath('Row') | ||
24 | + rows_obj = rows.flat_map do |el| | ||
25 | + el.elements.map do |inner| | ||
26 | + { | ||
27 | + name: inner.name, | ||
28 | + value: inner.children.text | ||
29 | + } | ||
30 | + end | ||
31 | + end.compact | ||
32 | + | ||
33 | + QueryObject.new( | ||
34 | + header_details_obj, | ||
35 | + rows_obj, | ||
36 | + doc.first_element_child.xpath('//RowsReturned').text.to_i | ||
37 | + ) | ||
38 | + end | ||
39 | + | ||
40 | + QueryObject = Struct.new(:header_details, :rows, :row_count) | ||
41 | + end | ||
42 | + end | ||
43 | + end | ||
44 | +end |
1 | +<?xml version="1.0" encoding="Windows-1252"?> | ||
2 | +<Browse xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:noNamespaceSchemaLocation="COMBRW.XSD"> | ||
3 | + <BrowseName><%= @browse_name %></BrowseName> | ||
4 | + <StartAtKey/> | ||
5 | + <StartCondition><%= @start_condition %></StartCondition> | ||
6 | + <ReturnRows><%= @return_rows %></ReturnRows> | ||
7 | + <% for @filter in @filters %> | ||
8 | + <Filter> | ||
9 | + <ColumnFilterName><%= @filter[:name] %></ColumnFilterName> | ||
10 | + <ColumnFilterValue><%= @filter[:value] %></ColumnFilterValue> | ||
11 | + </Filter> | ||
12 | + <% end %> | ||
13 | + <BrowseDetails> | ||
14 | + <TableName><%= @table_name %></TableName> | ||
15 | + <Title><%= @title %></Title> | ||
16 | + <% for @column in @columns %> | ||
17 | + <Column> | ||
18 | + <% unless @column[:name].nil? %><ColumnName><%= @column[:name] %></ColumnName><% end %> | ||
19 | + <% unless @column[:description].nil? %><ColumnDescription><%= @column[:description] %></ColumnDescription><% end %> | ||
20 | + <% unless @column[:key].nil? %><ColumnKey><%= @column[:key] %></ColumnKey><% end %> | ||
21 | + </Column> | ||
22 | + <% end %> | ||
23 | + </BrowseDetails> | ||
24 | +</Browse> | ||
25 | + |
1 | +<?xml version="1.0" encoding="Windows-1252"?> | ||
2 | +<Fetch xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:noNamespaceSchemaLocation="COMFCH.XSD"> | ||
3 | + <TableName><%= @table_name %></TableName> | ||
4 | + <Key><%= @key %></Key> | ||
5 | + <% unless @optional_keys.empty? %> | ||
6 | + <% @optional_keys.each_with_index do |key, i| %> | ||
7 | + <<%= "OptionalKey#{ i + 1 }" %>><%= key[:value] %></<%= "OptionalKey#{ i + 1 }" %>> | ||
8 | + <% end %> | ||
9 | + <% end %> | ||
10 | + <FullKeyProvided><%= @full_key_provided ? "N" : "Y" %></FullKeyProvided> | ||
11 | + <DefaultType><%= @default_type %></DefaultType> | ||
12 | + <EspressoFetch><%= @espresso_fetch ? "N" : "Y" %></EspressoFetch> | ||
13 | +</Fetch> | ||
14 | + |
1 | +<?xml version="1.0" encoding="Windows-1252"?> | ||
2 | +<Query xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:noNamespaceSchemaLocation="COMFND.XSD"> | ||
3 | + <TableName><%= @table_name %></TableName> | ||
4 | + <ReturnRows><%= @return_rows %></ReturnRows> | ||
5 | + <Columns> | ||
6 | + <% for column in @columns %> | ||
7 | + <Column><%= column[:name] %></Column> | ||
8 | + <% end %> | ||
9 | + </Columns> | ||
10 | + <% unless @expressions.empty? %> | ||
11 | + <Where> | ||
12 | + <% for expression in @expressions %> | ||
13 | + <Expression> | ||
14 | + <OpenBracket>(</OpenBracket> | ||
15 | + <% unless expression[:andor].nil? %> | ||
16 | + <AndOr><%= expression[:andor] %></AndOr> | ||
17 | + <% end %> | ||
18 | + <Column><%= expression[:column] %></Column> | ||
19 | + <Condition><%= expression[:condition] %></Condition> | ||
20 | + <Value><%= expression[:value] %></Value> | ||
21 | + <CloseBracket>)</CloseBracket> | ||
22 | + </Expression> | ||
23 | + <% end %> | ||
24 | + </Where> | ||
25 | + <% end %> | ||
26 | + <OrderBy> | ||
27 | + <Column><%= @order_by %></Column> | ||
28 | + </OrderBy> | ||
29 | +</Query> |
lib/syspro/errors.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
2 | class SysproError < StandardError | 4 | class SysproError < StandardError |
3 | attr_reader :message, :response, :code, :http_body, :http_headers, | 5 | attr_reader :message, :response, :code, :http_body, :http_headers, |
@@ -16,8 +18,8 @@ module Syspro | @@ -16,8 +18,8 @@ module Syspro | ||
16 | end | 18 | end |
17 | 19 | ||
18 | def to_s | 20 | def to_s |
19 | - status_string = @http_status.nil? ? "" : "(Status #{@http_status}) " | ||
20 | - id_string = @request_id.nil? ? "" : "(Request #{@request_id}) " | 21 | + status_string = @http_status.nil? ? '' : "(Status #{@http_status}) " |
22 | + id_string = @request_id.nil? ? '' : "(Request #{@request_id}) " | ||
21 | "#{status_string}#{id_string}#{@message}" | 23 | "#{status_string}#{id_string}#{@message}" |
22 | end | 24 | end |
23 | end | 25 | end |
@@ -30,5 +32,4 @@ module Syspro | @@ -30,5 +32,4 @@ module Syspro | ||
30 | 32 | ||
31 | class ApiError < SysproError | 33 | class ApiError < SysproError |
32 | end | 34 | end |
33 | - | ||
34 | end | 35 | end |
lib/syspro/get_logon_profile.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
2 | class GetLogonProfile < ApiResource | 4 | class GetLogonProfile < ApiResource |
3 | def self.get_logon_profile(user_id) | 5 | def self.get_logon_profile(user_id) |
4 | - params = { "UserId" => user_id } | ||
5 | - resp = self.request(:get, resource_url, params) | 6 | + params = { 'UserId' => user_id } |
7 | + resp = request(:get, resource_url, params) | ||
6 | parse_response(resp[0]) | 8 | parse_response(resp[0]) |
7 | end | 9 | end |
8 | 10 | ||
9 | def resource_url | 11 | def resource_url |
10 | - "/GetLogonProfile" | 12 | + '/GetLogonProfile' |
11 | end | 13 | end |
12 | 14 | ||
13 | - def self.parse_response(resp) | 15 | + def self.parse_response(resp) # rubocop:disable Metrics/MethodLength |
14 | doc = resp.data | 16 | doc = resp.data |
15 | 17 | ||
16 | - UserProfile.new( | ||
17 | - doc.xpath("//CompanyName").text, | ||
18 | - doc.xpath("//OperatorCode").text, | ||
19 | - doc.xpath("//OperatorGroup").text, | ||
20 | - doc.xpath("//OperatorEmailAddress").text, | ||
21 | - doc.xpath("//OperatorLocation").text, | ||
22 | - doc.xpath("//OperatorLanguageCode").text, | ||
23 | - doc.xpath("//SystemLanguage").text, | ||
24 | - doc.xpath("//AccountingDate").text, | ||
25 | - doc.xpath("//CompanyDate").text, | ||
26 | - doc.xpath("//DefaultArBranch").text, | ||
27 | - doc.xpath("//DefaultApBranch").text, | ||
28 | - doc.xpath("//DefaultBank").text, | ||
29 | - doc.xpath("//DefaultWarehouse").text, | ||
30 | - doc.xpath("//DefaultCustomer").text, | ||
31 | - doc.xpath("//SystemSiteId").text, | ||
32 | - doc.xpath("//SystemNationalityCode").text, | ||
33 | - doc.xpath("//LocalCurrencyCode").text, | ||
34 | - doc.xpath("//CurrencyDescription").text, | ||
35 | - doc.xpath("//DefaultRequisitionUser").text, | ||
36 | - doc.xpath("//XMLToHTMLTransform").text, | ||
37 | - doc.xpath("//CssStyle").text, | ||
38 | - doc.xpath("//CssSuffix").text, | ||
39 | - doc.xpath("//DecimalFormat").text, | ||
40 | - doc.xpath("//DateFormat").text, | ||
41 | - doc.xpath("//FunctionalRole").text, | ||
42 | - doc.xpath("//DatabaseType").text, | ||
43 | - doc.xpath("//SysproVersion").text, | ||
44 | - doc.xpath("//EnetVersion").text, | ||
45 | - doc.xpath("//SysproServerBitWidth").text, | 18 | + OpenStruct.new( |
19 | + company_name: doc.xpath('//CompanyName').text, | ||
20 | + operator_code: doc.xpath('//OperatorCode').text, | ||
21 | + operator_code: doc.xpath('//OperatorGroup').text, | ||
22 | + operator_email_address: doc.xpath('//OperatorEmailAddress').text, | ||
23 | + operator_location: doc.xpath('//OperatorLocation').text, | ||
24 | + operator_language_code: doc.xpath('//OperatorLanguageCode').text, | ||
25 | + system_language: doc.xpath('//SystemLanguage').text, | ||
26 | + accounting_date: doc.xpath('//AccountingDate').text, | ||
27 | + company_date: doc.xpath('//CompanyDate').text, | ||
28 | + default_ar_branch: doc.xpath('//DefaultArBranch').text, | ||
29 | + default_ap_branch: doc.xpath('//DefaultApBranch').text, | ||
30 | + default_bank: doc.xpath('//DefaultBank').text, | ||
31 | + default_warehouse: doc.xpath('//DefaultWarehouse').text, | ||
32 | + default_customer: doc.xpath('//DefaultCustomer').text, | ||
33 | + system_site_id: doc.xpath('//SystemSiteId').text, | ||
34 | + system_nationality_code: doc.xpath('//SystemNationalityCode').text, | ||
35 | + local_currency_code: doc.xpath('//LocalCurrencyCode').text, | ||
36 | + currency_description: doc.xpath('//CurrencyDescription').text, | ||
37 | + default_requisition_user: doc.xpath('//DefaultRequisitionUser').text, | ||
38 | + xml_to_html_transform: doc.xpath('//XMLToHTMLTransform').text, | ||
39 | + css_style: doc.xpath('//CssStyle').text, | ||
40 | + css_suffix: doc.xpath('//CssSuffix').text, | ||
41 | + decimal_format: doc.xpath('//DecimalFormat').text, | ||
42 | + date_format: doc.xpath('//DateFormat').text, | ||
43 | + functional_role: doc.xpath('//FunctionalRole').text, | ||
44 | + database_type: doc.xpath('//DatabaseType').text, | ||
45 | + syspro_version: doc.xpath('//SysproVersion').text, | ||
46 | + enet_version: doc.xpath('//EnetVersion').text, | ||
47 | + syspro_server_bit_width: doc.xpath('//SysproServerBitWidth').text | ||
46 | ) | 48 | ) |
47 | end | 49 | end |
48 | private_class_method :parse_response | 50 | private_class_method :parse_response |
49 | - | ||
50 | - UserProfile = Struct.new(:company_name, :operator_code, :operator_group, :operator_email_address, | ||
51 | - :operator_location, :operator_language_code, :system_language, :accounting_date, | ||
52 | - :company_date, :default_ar_branch, :default_ap_branch, :default_bank, :default_warehouse, | ||
53 | - :default_customer, :system_site_id, :system_nationality_code, :local_currency_code, | ||
54 | - :currency_description, :default_requisition_user, :xml_to_html_transform, :css_style, | ||
55 | - :css_suffix, :decimal_format, :date_format, :functional_role, :database_type, :syspro_version, | ||
56 | - :enet_version, :syspro_server_bit_width) | ||
57 | end | 51 | end |
58 | end | 52 | end |
59 | - |
lib/syspro/get_version.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
2 | class GetVersion < ApiResource | 4 | class GetVersion < ApiResource |
3 | def self.get_version | 5 | def self.get_version |
4 | - resp = self.request(:get, resource_url) | 6 | + resp = request(:get, resource_url) |
5 | VersionObject.new(resp[0].http_body) | 7 | VersionObject.new(resp[0].http_body) |
6 | end | 8 | end |
7 | 9 | ||
8 | def resource_url | 10 | def resource_url |
9 | - "/GetVersion" | 11 | + '/GetVersion' |
10 | end | 12 | end |
11 | 13 | ||
12 | VersionObject = Struct.new(:version) | 14 | VersionObject = Struct.new(:version) |
13 | end | 15 | end |
14 | end | 16 | end |
15 | - |
lib/syspro/logoff.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
2 | class Logoff < ApiResource | 4 | class Logoff < ApiResource |
3 | def self.logoff(user_id) | 5 | def self.logoff(user_id) |
4 | - params = { "UserId" => user_id } | ||
5 | - resp = self.request(:get, resource_url, params) | 6 | + params = { 'UserId' => user_id } |
7 | + resp = request(:get, resource_url, params) | ||
6 | 8 | ||
7 | - if resp[0].http_body == "0" | 9 | + if resp[0].http_body == '0' |
8 | true | 10 | true |
9 | else | 11 | else |
10 | resp[0].http_body | 12 | resp[0].http_body |
@@ -12,7 +14,7 @@ module Syspro | @@ -12,7 +14,7 @@ module Syspro | ||
12 | end | 14 | end |
13 | 15 | ||
14 | def resource_url | 16 | def resource_url |
15 | - "/Logoff" | 17 | + '/Logoff' |
16 | end | 18 | end |
17 | end | 19 | end |
18 | end | 20 | end |
lib/syspro/logon.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
2 | class Logon < ApiResource | 4 | class Logon < ApiResource |
3 | def self.logon(username, password, company_id, company_password = nil) | 5 | def self.logon(username, password, company_id, company_password = nil) |
4 | params = { | 6 | params = { |
5 | - "Operator" => username, | ||
6 | - "OperatorPassword" => password, | ||
7 | - "CompanyId" => company_id, | ||
8 | - "CompanyPassword" => company_password | 7 | + 'Operator' => username, |
8 | + 'OperatorPassword' => password, | ||
9 | + 'CompanyId' => company_id, | ||
10 | + 'CompanyPassword' => company_password | ||
9 | } | 11 | } |
10 | - resp = self.request(:get, resource_url, params) | 12 | + resp = request(:get, resource_url, params) |
11 | UserIdObject.new(resp[0].http_body) | 13 | UserIdObject.new(resp[0].http_body) |
12 | end | 14 | end |
13 | 15 | ||
14 | def resource_url | 16 | def resource_url |
15 | - "/Logon" | 17 | + '/Logon' |
16 | end | 18 | end |
17 | 19 | ||
18 | UserIdObject = Struct.new(:guid) | 20 | UserIdObject = Struct.new(:guid) |
19 | end | 21 | end |
20 | end | 22 | end |
21 | - |
lib/syspro/singleton_api_resource.rb
1 | -require_relative "api_resource" | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +require_relative 'api_resource' | ||
2 | 4 | ||
3 | module Syspro | 5 | module Syspro |
4 | class SingletonAPIResource < ApiResource | 6 | class SingletonAPIResource < ApiResource |
5 | def self.resource_url | 7 | def self.resource_url |
6 | if self == SingletonAPIResource | 8 | if self == SingletonAPIResource |
7 | - raise NotImplementedError, "SingletonAPIResource is an abstract class. You should perform actions on its subclasses (Customer, etc.)" | 9 | + raise( |
10 | + NotImplementedError, | ||
11 | + 'SingletonAPIResource is an abstract class. You should perform actions on its subclasses (Customer, etc.)' # rubocop:disable Metrics/LineLength | ||
12 | + ) | ||
8 | end | 13 | end |
9 | "/#{CGI.escape(class_name.downcase)}" | 14 | "/#{CGI.escape(class_name.downcase)}" |
10 | end | 15 | end |
lib/syspro/syspro_client.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
2 | - class SysproClient | 4 | + # This class is the main syspro client |
5 | + class SysproClient # rubocop:disable Metrics/ClassLength | ||
3 | attr_accessor :conn, :api_base | 6 | attr_accessor :conn, :api_base |
4 | 7 | ||
5 | @verify_ssl_warned = false | 8 | @verify_ssl_warned = false |
@@ -13,7 +16,7 @@ module Syspro | @@ -13,7 +16,7 @@ module Syspro | ||
13 | Syspro::Logon.logon(username, password, company_id, company_password) | 16 | Syspro::Logon.logon(username, password, company_id, company_password) |
14 | end | 17 | end |
15 | 18 | ||
16 | - def get_syspro_version | 19 | + def get_syspro_version # rubocop:disable Naming/AccessorMethodName |
17 | Syspro::GetVersion.get_version | 20 | Syspro::GetVersion.get_version |
18 | end | 21 | end |
19 | 22 | ||
@@ -22,13 +25,13 @@ module Syspro | @@ -22,13 +25,13 @@ module Syspro | ||
22 | end | 25 | end |
23 | 26 | ||
24 | def self.default_client | 27 | def self.default_client |
25 | - Thread.current[:syspro_client_default_client] ||= SysproClient.new(default_conn) | 28 | + Thread.current[:syspro_client_default_client] ||= SysproClient.new(default_conn) # rubocop:disable Metrics/LineLength |
26 | end | 29 | end |
27 | 30 | ||
28 | # A default Faraday connection to be used when one isn't configured. This | 31 | # A default Faraday connection to be used when one isn't configured. This |
29 | # object should never be mutated, and instead instantiating your own | 32 | # object should never be mutated, and instead instantiating your own |
30 | # connection and wrapping it in a SysproClient object should be preferred. | 33 | # connection and wrapping it in a SysproClient object should be preferred. |
31 | - def self.default_conn | 34 | + def self.default_conn # rubocop:disable Metrics/MethodLength |
32 | # We're going to keep connections around so that we can take advantage | 35 | # We're going to keep connections around so that we can take advantage |
33 | # of connection re-use, so make sure that we have a separate connection | 36 | # of connection re-use, so make sure that we have a separate connection |
34 | # object per thread. | 37 | # object per thread. |
@@ -40,20 +43,21 @@ module Syspro | @@ -40,20 +43,21 @@ module Syspro | ||
40 | c.adapter Faraday.default_adapter | 43 | c.adapter Faraday.default_adapter |
41 | end | 44 | end |
42 | 45 | ||
43 | - # For now, we're not verifying SSL certificates. The warning will appear. | ||
44 | - #if Syspro.verify_ssl_certs | ||
45 | - #conn.ssl.verify = true | ||
46 | - #conn.ssl.cert_store = Syspro.ca_store | ||
47 | - #else | 46 | + # For now, we're not verifying SSL certificates. |
47 | + # The warning will appear. | ||
48 | + # if Syspro.verify_ssl_certs | ||
49 | + # conn.ssl.verify = true | ||
50 | + # conn.ssl.cert_store = Syspro.ca_store | ||
51 | + # else | ||
48 | conn.ssl.verify = false | 52 | conn.ssl.verify = false |
49 | 53 | ||
50 | unless @verify_ssl_warned | 54 | unless @verify_ssl_warned |
51 | @verify_ssl_warned = true | 55 | @verify_ssl_warned = true |
52 | - $stderr.puts("WARNING: Running without SSL cert verification. " \ | ||
53 | - "You should never do this in production. " \ | 56 | + warn('WARNING: Running without SSL cert verification. ' \ |
57 | + 'You should never do this in production. ' \ | ||
54 | "Execute 'Syspro.verify_ssl_certs = true' to enable verification.") | 58 | "Execute 'Syspro.verify_ssl_certs = true' to enable verification.") |
55 | end | 59 | end |
56 | - #end | 60 | + # end |
57 | 61 | ||
58 | conn | 62 | conn |
59 | end | 63 | end |
@@ -77,9 +81,9 @@ module Syspro | @@ -77,9 +81,9 @@ module Syspro | ||
77 | end | 81 | end |
78 | end | 82 | end |
79 | 83 | ||
80 | - def execute_request(method, path, user_id: nil, api_base: nil, headers: {}, params: {}) | 84 | + def execute_request(method, path, user_id: nil, api_base: nil, headers: {}, params: {}) # rubocop:disable Metrics/LineLength, Metrics/MethodLength |
81 | api_base ||= Syspro.api_base | 85 | api_base ||= Syspro.api_base |
82 | - user_id ||= "" | 86 | + user_id ||= '' |
83 | 87 | ||
84 | params = Util.objects_to_ids(params) | 88 | params = Util.objects_to_ids(params) |
85 | url = api_url(path, api_base) | 89 | url = api_url(path, api_base) |
@@ -91,7 +95,7 @@ module Syspro | @@ -91,7 +95,7 @@ module Syspro | ||
91 | when :get, :head, :delete | 95 | when :get, :head, :delete |
92 | query_params = params | 96 | query_params = params |
93 | else | 97 | else |
94 | - body = if headers[:content_type] && headers[:content_type] == "multipart/form-data" | 98 | + body = if headers[:content_type] && headers[:content_type] == 'multipart/form-data' # rubocop:disable Metrics/LineLength |
95 | params | 99 | params |
96 | else | 100 | else |
97 | Util.encode_parameters(params) | 101 | Util.encode_parameters(params) |
@@ -108,7 +112,7 @@ module Syspro | @@ -108,7 +112,7 @@ module Syspro | ||
108 | context.method = method | 112 | context.method = method |
109 | context.path = path | 113 | context.path = path |
110 | context.user_id = user_id | 114 | context.user_id = user_id |
111 | - context.query_params = query_params ? Util.encode_parameters(query_params) : nil | 115 | + context.query_params = query_params ? Util.encode_parameters(query_params) : nil # rubocop:disable Metrics/LineLength |
112 | 116 | ||
113 | http_resp = execute_request_with_rescues(api_base, context) do | 117 | http_resp = execute_request_with_rescues(api_base, context) do |
114 | conn.run_request(method, url, body, headers) do |req| | 118 | conn.run_request(method, url, body, headers) do |req| |
@@ -135,22 +139,22 @@ module Syspro | @@ -135,22 +139,22 @@ module Syspro | ||
135 | http_status: status, http_body: body) | 139 | http_status: status, http_body: body) |
136 | end | 140 | end |
137 | 141 | ||
138 | - def api_url(url = "", api_base = nil) | 142 | + def api_url(url = '', api_base = nil) |
139 | (api_base || Syspro.api_base) + url | 143 | (api_base || Syspro.api_base) + url |
140 | end | 144 | end |
141 | 145 | ||
142 | - def request_headers(method) | 146 | + def request_headers(_method) |
143 | user_agent = "Syspro/7 RubyBindings/#{Syspro::VERSION}" | 147 | user_agent = "Syspro/7 RubyBindings/#{Syspro::VERSION}" |
144 | 148 | ||
145 | headers = { | 149 | headers = { |
146 | - "User-Agent" => user_agent, | ||
147 | - "Content-Type" => "application/x-www-form-urlencoded", | 150 | + 'User-Agent' => user_agent, |
151 | + 'Content-Type' => 'application/x-www-form-urlencoded' | ||
148 | } | 152 | } |
149 | 153 | ||
150 | headers | 154 | headers |
151 | end | 155 | end |
152 | 156 | ||
153 | - def execute_request_with_rescues(api_base, context) | 157 | + def execute_request_with_rescues(api_base, context) # rubocop:disable Metrics/LineLength, Metrics/MethodLength |
154 | num_retries = 0 | 158 | num_retries = 0 |
155 | begin | 159 | begin |
156 | request_start = Time.now | 160 | request_start = Time.now |
@@ -159,8 +163,8 @@ module Syspro | @@ -159,8 +163,8 @@ module Syspro | ||
159 | log_response(context, request_start, resp.status, resp.body) | 163 | log_response(context, request_start, resp.status, resp.body) |
160 | 164 | ||
161 | # We rescue all exceptions from a request so that we have an easy spot to | 165 | # We rescue all exceptions from a request so that we have an easy spot to |
162 | - # implement our retry logic across the board. We'll re-raise if it's a type | ||
163 | - # of exception that we didn't expect to handle. | 166 | + # implement our retry logic across the board. We'll re-raise if it's a |
167 | + # type of exception that we didn't expect to handle. | ||
164 | rescue StandardError => e | 168 | rescue StandardError => e |
165 | if e.respond_to?(:response) && e.response | 169 | if e.respond_to?(:response) && e.response |
166 | log_response(context, request_start, | 170 | log_response(context, request_start, |
@@ -178,9 +182,9 @@ module Syspro | @@ -178,9 +182,9 @@ module Syspro | ||
178 | case e | 182 | case e |
179 | when Faraday::ClientError | 183 | when Faraday::ClientError |
180 | if e.response | 184 | if e.response |
181 | - handle_error_response(e.response, error_context) | 185 | + handle_error_response(e.response, context) |
182 | else | 186 | else |
183 | - handle_network_error(e, error_context, num_retries, api_base) | 187 | + handle_network_error(e, context, num_retries, api_base) |
184 | end | 188 | end |
185 | 189 | ||
186 | # Only handle errors when we know we can do so, and re-raise otherwise. | 190 | # Only handle errors when we know we can do so, and re-raise otherwise. |
@@ -193,7 +197,36 @@ module Syspro | @@ -193,7 +197,36 @@ module Syspro | ||
193 | resp | 197 | resp |
194 | end | 198 | end |
195 | 199 | ||
196 | - def self.should_retry?(e, num_retries) | 200 | + def handle_network_error(e, context, num_retries, api_base = nil) # rubocop:disable Metrics/LineLength, Metrics/MethodLength, Naming/UncommunicativeMethodParamName |
201 | + Util.log_error('Syspro network error', | ||
202 | + error_message: e.message, | ||
203 | + request_id: context.request_id) | ||
204 | + | ||
205 | + case e | ||
206 | + when Faraday::ConnectionFailed | ||
207 | + message = 'Unexpected error communicating when trying to connect to Syspro.' # rubocop:disable Metrics/LineLength | ||
208 | + | ||
209 | + when Faraday::SSLError | ||
210 | + message = 'Could not establish a secure connection to Syspro.' | ||
211 | + | ||
212 | + when Faraday::TimeoutError | ||
213 | + api_base ||= Syspro.api_base | ||
214 | + message = "Could not connect to Syspro (#{api_base}). " \ | ||
215 | + 'Please check your internet connection and try again. ' \ | ||
216 | + 'If this problem persists, you should check your Syspro service status.' # rubocop:disable Metrics/LineLength | ||
217 | + | ||
218 | + else | ||
219 | + message = 'Unexpected error communicating with Syspro. ' \ | ||
220 | + 'If this problem persists, talk to your Syspro implementation team.' | ||
221 | + | ||
222 | + end | ||
223 | + | ||
224 | + message += " Request was retried #{num_retries} times." if num_retries.positive? # rubocop:disable Metrics/LineLength | ||
225 | + | ||
226 | + raise ApiConnectionError, message + "\n\n(Network error: #{e.message})" | ||
227 | + end | ||
228 | + | ||
229 | + def self.should_retry?(e, num_retries) # rubocop:disable Metrics/LineLength, Naming/UncommunicativeMethodParamName | ||
197 | return false if num_retries >= Syspro.max_network_retries | 230 | return false if num_retries >= Syspro.max_network_retries |
198 | 231 | ||
199 | # Retry on timeout-related problems (either on open or read). | 232 | # Retry on timeout-related problems (either on open or read). |
@@ -213,20 +246,20 @@ module Syspro | @@ -213,20 +246,20 @@ module Syspro | ||
213 | end | 246 | end |
214 | 247 | ||
215 | def log_request(context, num_retries) | 248 | def log_request(context, num_retries) |
216 | - Util.log_info("Request to Syspro API", | 249 | + Util.log_info('Request to Syspro API', |
217 | account: context.account, | 250 | account: context.account, |
218 | api_version: context.api_version, | 251 | api_version: context.api_version, |
219 | method: context.method, | 252 | method: context.method, |
220 | num_retries: num_retries, | 253 | num_retries: num_retries, |
221 | path: context.path) | 254 | path: context.path) |
222 | - Util.log_debug("Request details", | 255 | + Util.log_debug('Request details', |
223 | body: context.body, | 256 | body: context.body, |
224 | query_params: context.query_params) | 257 | query_params: context.query_params) |
225 | end | 258 | end |
226 | private :log_request | 259 | private :log_request |
227 | 260 | ||
228 | - def log_response(context, request_start, status, body) | ||
229 | - Util.log_info("Response from Syspro API", | 261 | + def log_response(context, request_start, status, body) # rubocop:disable Metrics/LineLength, Metrics/MethodLength |
262 | + Util.log_info('Response from Syspro API', | ||
230 | account: context.account, | 263 | account: context.account, |
231 | api_version: context.api_version, | 264 | api_version: context.api_version, |
232 | elapsed: Time.now - request_start, | 265 | elapsed: Time.now - request_start, |
@@ -234,14 +267,14 @@ module Syspro | @@ -234,14 +267,14 @@ module Syspro | ||
234 | path: context.path, | 267 | path: context.path, |
235 | request_id: context.request_id, | 268 | request_id: context.request_id, |
236 | status: status) | 269 | status: status) |
237 | - Util.log_debug("Response details", | 270 | + Util.log_debug('Response details', |
238 | body: body, | 271 | body: body, |
239 | request_id: context.request_id) | 272 | request_id: context.request_id) |
240 | end | 273 | end |
241 | private :log_response | 274 | private :log_response |
242 | 275 | ||
243 | - def log_response_error(context, request_start, e) | ||
244 | - Util.log_error("Request error", | 276 | + def log_response_error(context, request_start, e) # rubocop:disable Metrics/LineLength, Naming/UncommunicativeMethodParamName |
277 | + Util.log_error('Request error', | ||
245 | elapsed: Time.now - request_start, | 278 | elapsed: Time.now - request_start, |
246 | error_message: e.message, | 279 | error_message: e.message, |
247 | method: context.method, | 280 | method: context.method, |
@@ -249,6 +282,26 @@ module Syspro | @@ -249,6 +282,26 @@ module Syspro | ||
249 | end | 282 | end |
250 | private :log_response_error | 283 | private :log_response_error |
251 | 284 | ||
285 | + def handle_error_response(http_resp, context) # rubocop:disable Metrics/LineLength, Metrics/MethodLength | ||
286 | + begin | ||
287 | + resp = SysproResponse.from_faraday_hash(http_resp) | ||
288 | + error_data = resp.data[:error] | ||
289 | + | ||
290 | + raise SysproError, 'Indeterminate error' unless error_data | ||
291 | + rescue Nokogiri::XML::SyntaxError, SysproError | ||
292 | + raise general_api_error(http_resp[:status], http_resp[:body]) | ||
293 | + end | ||
294 | + | ||
295 | + error = if error_data.is_a?(String) | ||
296 | + specific_oauth_error(resp, error_data, context) | ||
297 | + else | ||
298 | + specific_api_error(resp, error_data, context) | ||
299 | + end | ||
300 | + | ||
301 | + error.response = resp | ||
302 | + raise(error) | ||
303 | + end | ||
304 | + | ||
252 | # RequestLogContext stores information about a request that's begin made so | 305 | # 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 | 306 | # that we can log certain information. It's useful because it means that we |
254 | # don't have to pass around as many parameters. | 307 | # don't have to pass around as many parameters. |
@@ -267,56 +320,55 @@ module Syspro | @@ -267,56 +320,55 @@ module Syspro | ||
267 | # in so that we can generate a rich user agent header to help debug | 320 | # in so that we can generate a rich user agent header to help debug |
268 | # integrations. | 321 | # integrations. |
269 | class SystemProfiler | 322 | class SystemProfiler |
270 | - def self.uname | ||
271 | - if File.exist?("/proc/version") | ||
272 | - File.read("/proc/version").strip | 323 | + def self.uname # rubocop:disable Metrics/MethodLength |
324 | + if File.exist?('/proc/version') | ||
325 | + File.read('/proc/version').strip | ||
273 | else | 326 | else |
274 | - case RbConfig::CONFIG["host_os"] | 327 | + case RbConfig::CONFIG['host_os'] |
275 | when /linux|darwin|bsd|sunos|solaris|cygwin/i | 328 | when /linux|darwin|bsd|sunos|solaris|cygwin/i |
276 | uname_from_system | 329 | uname_from_system |
277 | when /mswin|mingw/i | 330 | when /mswin|mingw/i |
278 | uname_from_system_ver | 331 | uname_from_system_ver |
279 | else | 332 | else |
280 | - "unknown platform" | 333 | + 'unknown platform' |
281 | end | 334 | end |
282 | end | 335 | end |
283 | end | 336 | end |
284 | 337 | ||
285 | def self.uname_from_system | 338 | def self.uname_from_system |
286 | - (`uname -a 2>/dev/null` || "").strip | 339 | + (`uname -a 2>/dev/null` || '').strip |
287 | rescue Errno::ENOENT | 340 | rescue Errno::ENOENT |
288 | - "uname executable not found" | 341 | + 'uname executable not found' |
289 | rescue Errno::ENOMEM # couldn't create subprocess | 342 | rescue Errno::ENOMEM # couldn't create subprocess |
290 | - "uname lookup failed" | 343 | + 'uname lookup failed' |
291 | end | 344 | end |
292 | 345 | ||
293 | def self.uname_from_system_ver | 346 | def self.uname_from_system_ver |
294 | - (`ver` || "").strip | 347 | + (`ver` || '').strip |
295 | rescue Errno::ENOENT | 348 | rescue Errno::ENOENT |
296 | - "ver executable not found" | 349 | + 'ver executable not found' |
297 | rescue Errno::ENOMEM # couldn't create subprocess | 350 | rescue Errno::ENOMEM # couldn't create subprocess |
298 | - "uname lookup failed" | 351 | + 'uname lookup failed' |
299 | end | 352 | end |
300 | 353 | ||
301 | def initialize | 354 | def initialize |
302 | @uname = self.class.uname | 355 | @uname = self.class.uname |
303 | end | 356 | end |
304 | 357 | ||
305 | - def user_agent | ||
306 | - lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})" | 358 | + def user_agent # rubocop:disable Metrics/MethodLength |
359 | + lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})" # rubocop:disable Metrics/LineLength | ||
307 | 360 | ||
308 | { | 361 | { |
309 | application: Syspro.app_info, | 362 | application: Syspro.app_info, |
310 | bindings_version: Syspro::VERSION, | 363 | bindings_version: Syspro::VERSION, |
311 | - lang: "ruby", | 364 | + lang: 'ruby', |
312 | lang_version: lang_version, | 365 | lang_version: lang_version, |
313 | platform: RUBY_PLATFORM, | 366 | platform: RUBY_PLATFORM, |
314 | - engine: defined?(RUBY_ENGINE) ? RUBY_ENGINE : "", | 367 | + engine: defined?(RUBY_ENGINE) ? RUBY_ENGINE : '', |
315 | uname: @uname, | 368 | uname: @uname, |
316 | - hostname: Socket.gethostname, | 369 | + hostname: Socket.gethostname |
317 | }.delete_if { |_k, v| v.nil? } | 370 | }.delete_if { |_k, v| v.nil? } |
318 | end | 371 | end |
319 | end | 372 | end |
320 | end | 373 | end |
321 | end | 374 | end |
322 | - |
lib/syspro/syspro_object.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
4 | + # This class represents a syspro response | ||
2 | class SysproObject | 5 | class SysproObject |
3 | include Enumerable | 6 | include Enumerable |
4 | 7 | ||
@@ -18,7 +21,8 @@ module Syspro | @@ -18,7 +21,8 @@ module Syspro | ||
18 | # considered to be equal if they have the same set of values and each one | 21 | # considered to be equal if they have the same set of values and each one |
19 | # of those values is the same. | 22 | # of those values is the same. |
20 | def ==(other) | 23 | def ==(other) |
21 | - other.is_a?(SysproObject) && @values == other.instance_variable_get(:@values) | 24 | + other.is_a?(SysproObject) && |
25 | + @values == other.instance_variable_get(:@values) | ||
22 | end | 26 | end |
23 | 27 | ||
24 | def to_s(*_args) | 28 | def to_s(*_args) |
@@ -26,8 +30,8 @@ module Syspro | @@ -26,8 +30,8 @@ module Syspro | ||
26 | end | 30 | end |
27 | 31 | ||
28 | def inspect | 32 | def inspect |
29 | - id_string = respond_to?(:id) && !id.nil? ? " id=#{id}" : "" | ||
30 | - "#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values) | 33 | + id_string = respond_to?(:id) && !id.nil? ? " id=#{id}" : '' |
34 | + "#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values) # rubocop:disable Metrics/LineLength | ||
31 | end | 35 | end |
32 | 36 | ||
33 | def keys | 37 | def keys |
@@ -38,9 +42,9 @@ module Syspro | @@ -38,9 +42,9 @@ module Syspro | ||
38 | @values.values | 42 | @values.values |
39 | end | 43 | end |
40 | 44 | ||
41 | - def to_hash | 45 | + def to_hash # rubocop:disable Metrics/MethodLength |
42 | maybe_to_hash = lambda do |value| | 46 | maybe_to_hash = lambda do |value| |
43 | - value && value.respond_to?(:to_hash) ? value.to_hash : value | 47 | + value&.respond_to?(:to_hash) ? value.to_hash : value |
44 | end | 48 | end |
45 | 49 | ||
46 | @values.each_with_object({}) do |(key, value), acc| | 50 | @values.each_with_object({}) do |(key, value), acc| |
@@ -57,11 +61,9 @@ module Syspro | @@ -57,11 +61,9 @@ module Syspro | ||
57 | @values.each(&blk) | 61 | @values.each(&blk) |
58 | end | 62 | end |
59 | 63 | ||
60 | - private | ||
61 | - | ||
62 | # Produces a deep copy of the given object including support for arrays, | 64 | # Produces a deep copy of the given object including support for arrays, |
63 | # hashes, and SysproObjects. | 65 | # hashes, and SysproObjects. |
64 | - def self.deep_copy(obj) | 66 | + def self.deep_copy(obj) # rubocop:disable Metrics/MethodLength |
65 | case obj | 67 | case obj |
66 | when Array | 68 | when Array |
67 | obj.map { |e| deep_copy(e) } | 69 | obj.map { |e| deep_copy(e) } |
@@ -82,6 +84,5 @@ module Syspro | @@ -82,6 +84,5 @@ module Syspro | ||
82 | end | 84 | end |
83 | end | 85 | end |
84 | private_class_method :deep_copy | 86 | private_class_method :deep_copy |
85 | - | ||
86 | end | 87 | end |
87 | end | 88 | end |
lib/syspro/syspro_response.rb
1 | -require "nokogiri" | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +require 'nokogiri' | ||
2 | 4 | ||
3 | module Syspro | 5 | module Syspro |
6 | + # This class represents a syspro response | ||
4 | class SysproResponse | 7 | class SysproResponse |
5 | attr_accessor :data, :http_body, :http_headers, :http_status, :request_id | 8 | attr_accessor :data, :http_body, :http_headers, :http_status, :request_id |
6 | 9 | ||
@@ -12,7 +15,7 @@ module Syspro | @@ -12,7 +15,7 @@ module Syspro | ||
12 | resp.data = Nokogiri::XML(resp.http_body) | 15 | resp.data = Nokogiri::XML(resp.http_body) |
13 | resp.http_headers = http_resp[:headers] | 16 | resp.http_headers = http_resp[:headers] |
14 | resp.http_status = http_resp[:status] | 17 | resp.http_status = http_resp[:status] |
15 | - resp.request_id = http_resp[:headers]["Request-Id"] | 18 | + resp.request_id = http_resp[:headers]['Request-Id'] |
16 | resp | 19 | resp |
17 | end | 20 | end |
18 | 21 | ||
@@ -23,7 +26,7 @@ module Syspro | @@ -23,7 +26,7 @@ module Syspro | ||
23 | resp.data = Nokogiri::XML(resp.http_body) | 26 | resp.data = Nokogiri::XML(resp.http_body) |
24 | resp.http_headers = http_resp.headers | 27 | resp.http_headers = http_resp.headers |
25 | resp.http_status = http_resp.status | 28 | resp.http_status = http_resp.status |
26 | - resp.request_id = http_resp.headers["Request-Id"] | 29 | + resp.request_id = http_resp.headers['Request-Id'] |
27 | resp | 30 | resp |
28 | end | 31 | end |
29 | end | 32 | end |
lib/syspro/util.rb
1 | +# frozen_string_literal: true | ||
2 | + | ||
1 | module Syspro | 3 | module Syspro |
2 | - class Util | 4 | + # Utillity class |
5 | + class Util # rubocop:disable Metrics/ClassLength | ||
3 | # Options that a user is allowed to specify. | 6 | # Options that a user is allowed to specify. |
4 | OPTS_USER_SPECIFIED = Set[ | 7 | OPTS_USER_SPECIFIED = Set[ |
5 | :user_id | 8 | :user_id |
@@ -17,8 +20,7 @@ module Syspro | @@ -17,8 +20,7 @@ module Syspro | ||
17 | OPTS_USER_SPECIFIED + Set[:client] | 20 | OPTS_USER_SPECIFIED + Set[:client] |
18 | ).freeze | 21 | ).freeze |
19 | 22 | ||
20 | - | ||
21 | - def self.objects_to_ids(h) | 23 | + def self.objects_to_ids(h) # rubocop:disable Metrics/MethodLength, Metrics/LineLength, Naming/UncommunicativeMethodParamName |
22 | case h | 24 | case h |
23 | when ApiResource | 25 | when ApiResource |
24 | h.id | 26 | h.id |
@@ -45,13 +47,17 @@ module Syspro | @@ -45,13 +47,17 @@ module Syspro | ||
45 | # * +data+ - Hash of fields and values to be converted into a SysproObject. | 47 | # * +data+ - Hash of fields and values to be converted into a SysproObject. |
46 | # * +opts+ - Options for +SysproObject+ like an API key that will be reused | 48 | # * +opts+ - Options for +SysproObject+ like an API key that will be reused |
47 | # on subsequent API calls. | 49 | # on subsequent API calls. |
48 | - def self.convert_to_syspro_object(data, opts = {}) | 50 | + def self.convert_to_syspro_object(data, opts = {}) # rubocop:disable Metrics/LineLength, Metrics/MethodLength |
49 | case data | 51 | case data |
50 | when Array | 52 | when Array |
51 | data.map { |i| convert_to_syspro_object(i, opts) } | 53 | data.map { |i| convert_to_syspro_object(i, opts) } |
52 | when Hash | 54 | when Hash |
53 | - # Try converting to a known object class. If none available, fall back to generic SysproObject | ||
54 | - object_classes.fetch(data[:object], SysproObject).construct_from(data, opts) | 55 | + # Try converting to a known object class. |
56 | + # If none available, fall back to generic SysproObject | ||
57 | + object_classes.fetch( | ||
58 | + data[:object], | ||
59 | + SysproObject | ||
60 | + ).construct_from(data, opts) | ||
55 | else | 61 | else |
56 | data | 62 | data |
57 | end | 63 | end |
@@ -66,7 +72,7 @@ module Syspro | @@ -66,7 +72,7 @@ module Syspro | ||
66 | when Hash | 72 | when Hash |
67 | opts.clone | 73 | opts.clone |
68 | else | 74 | else |
69 | - raise TypeError, "normalize_opts expects a string or a hash" | 75 | + raise TypeError, 'normalize_opts expects a string or a hash' |
70 | end | 76 | end |
71 | end | 77 | end |
72 | 78 | ||
@@ -78,7 +84,7 @@ module Syspro | @@ -78,7 +84,7 @@ module Syspro | ||
78 | def self.normalize_headers(headers) | 84 | def self.normalize_headers(headers) |
79 | headers.each_with_object({}) do |(k, v), new_headers| | 85 | headers.each_with_object({}) do |(k, v), new_headers| |
80 | if k.is_a?(Symbol) | 86 | if k.is_a?(Symbol) |
81 | - k = titlecase_parts(k.to_s.tr("_", "-")) | 87 | + k = titlecase_parts(k.to_s.tr('_', '-')) |
82 | elsif k.is_a?(String) | 88 | elsif k.is_a?(String) |
83 | k = titlecase_parts(k) | 89 | k = titlecase_parts(k) |
84 | end | 90 | end |
@@ -89,10 +95,10 @@ module Syspro | @@ -89,10 +95,10 @@ module Syspro | ||
89 | 95 | ||
90 | def self.encode_parameters(params) | 96 | def self.encode_parameters(params) |
91 | Util.flatten_params(params) | 97 | Util.flatten_params(params) |
92 | - .map { |k, v| "#{url_encode(k)}=#{url_encode(v)}" }.join("&") | 98 | + .map { |k, v| "#{url_encode(k)}=#{url_encode(v)}" }.join('&') |
93 | end | 99 | end |
94 | 100 | ||
95 | - def self.flatten_params(params, parent_key = nil) | 101 | + def self.flatten_params(params, parent_key = nil) # rubocop:disable Metrics/LineLength, Metrics/MethodLength |
96 | result = [] | 102 | result = [] |
97 | 103 | ||
98 | # do not sort the final output because arrays (and arrays of hashes | 104 | # do not sort the final output because arrays (and arrays of hashes |
@@ -113,26 +119,41 @@ module Syspro | @@ -113,26 +119,41 @@ module Syspro | ||
113 | end | 119 | end |
114 | 120 | ||
115 | def self.log_error(message, data = {}) | 121 | def self.log_error(message, data = {}) |
116 | - if !Syspro.logger.nil? || | ||
117 | - !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_ERROR | ||
118 | - log_internal(message, data, color: :cyan, | ||
119 | - level: Syspro::LEVEL_ERROR, logger: Syspro.logger, out: $stderr) | 122 | + if !Syspro.logger.nil? || !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_ERROR # rubocop:disable Style/GuardClause, Metrics/LineLength |
123 | + log_internal( | ||
124 | + message, | ||
125 | + data, | ||
126 | + color: :cyan, | ||
127 | + level: Syspro::LEVEL_ERROR, | ||
128 | + logger: Syspro.logger, | ||
129 | + out: $stderr | ||
130 | + ) | ||
120 | end | 131 | end |
121 | end | 132 | end |
122 | 133 | ||
123 | def self.log_info(message, data = {}) | 134 | def self.log_info(message, data = {}) |
124 | - if !Syspro.logger.nil? || | ||
125 | - !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_INFO | ||
126 | - log_internal(message, data, color: :cyan, | ||
127 | - level: Syspro::LEVEL_INFO, logger: Syspro.logger, out: $stdout) | 135 | + if !Syspro.logger.nil? || !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_INFO # rubocop:disable Style/GuardClause, Metrics/LineLength |
136 | + log_internal( | ||
137 | + message, | ||
138 | + data, | ||
139 | + color: :cyan, | ||
140 | + level: Syspro::LEVEL_INFO, | ||
141 | + logger: Syspro.logger, | ||
142 | + out: $stdout | ||
143 | + ) | ||
128 | end | 144 | end |
129 | end | 145 | end |
130 | 146 | ||
131 | def self.log_debug(message, data = {}) | 147 | def self.log_debug(message, data = {}) |
132 | - if !Syspro.logger.nil? || | ||
133 | - !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_DEBUG | ||
134 | - log_internal(message, data, color: :blue, | ||
135 | - level: Syspro::LEVEL_DEBUG, logger: Syspro.logger, out: $stdout) | 148 | + if !Syspro.logger.nil? || !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_DEBUG # rubocop:disable Style/GuardClause, Metrics/LineLength |
149 | + log_internal( | ||
150 | + message, | ||
151 | + data, | ||
152 | + color: :blue, | ||
153 | + level: Syspro::LEVEL_DEBUG, | ||
154 | + logger: Syspro.logger, | ||
155 | + out: $stdout | ||
156 | + ) | ||
136 | end | 157 | end |
137 | end | 158 | end |
138 | 159 | ||
@@ -141,8 +162,47 @@ module Syspro | @@ -141,8 +162,47 @@ module Syspro | ||
141 | # Don't use strict form encoding by changing the square bracket control | 162 | # Don't use strict form encoding by changing the square bracket control |
142 | # characters back to their literals. This is fine by the server, and | 163 | # characters back to their literals. This is fine by the server, and |
143 | # makes these parameter strings easier to read. | 164 | # makes these parameter strings easier to read. |
144 | - gsub("%5B", "[").gsub("%5D", "]") | 165 | + gsub('%5B', '[').gsub('%5D', ']') |
145 | end | 166 | end |
167 | + | ||
168 | + # TODO: Make these named required arguments when we drop support for Ruby | ||
169 | + # 2.0. | ||
170 | + def self.log_internal(message, data = {}, color: nil, level: nil, logger: nil, out: nil) # rubocop:disable Metrics/LineLength, Metrics/AbcSize, Metrics/MethodLength, Metrics/ParameterLists | ||
171 | + data_str = data.reject { |_k, v| v.nil? }.map do |(k, v)| | ||
172 | + format( | ||
173 | + '%s=%s', # rubocop:disable Style/FormatStringToken | ||
174 | + colorize(k, color, !out.nil? && out.isatty), | ||
175 | + wrap_logfmt_value(v) | ||
176 | + ) | ||
177 | + end.join(' ') | ||
178 | + | ||
179 | + if !logger.nil? | ||
180 | + # the library's log levels are mapped to the same values as the | ||
181 | + # standard library's logger | ||
182 | + logger.log( | ||
183 | + level, | ||
184 | + format( | ||
185 | + 'message=%s %s', # rubocop:disable Style/FormatStringToken | ||
186 | + wrap_logfmt_value(message), | ||
187 | + data_str | ||
188 | + ) | ||
189 | + ) | ||
190 | + elsif out.isatty | ||
191 | + out.puts format( | ||
192 | + '%s %s %s', # rubocop:disable Style/FormatStringToken | ||
193 | + colorize(level_name(level)[0, 4].upcase, color, out.isatty), | ||
194 | + message, | ||
195 | + data_str | ||
196 | + ) | ||
197 | + else | ||
198 | + out.puts format( | ||
199 | + 'message=%s level=%s %s', # rubocop:disable Style/FormatStringToken | ||
200 | + wrap_logfmt_value(message), | ||
201 | + level_name(level), | ||
202 | + data_str | ||
203 | + ) | ||
204 | + end | ||
205 | + end | ||
206 | + private_class_method :log_internal | ||
146 | end | 207 | end |
147 | end | 208 | end |
148 | - |
lib/syspro/version.rb
syspro-ruby.gemspec
1 | -lib = File.expand_path("../lib", __FILE__) | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +lib = File.expand_path('lib', __dir__) | ||
2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) |
3 | -require "syspro/version" | 5 | +require 'syspro/version' |
4 | 6 | ||
5 | Gem::Specification.new do |spec| | 7 | Gem::Specification.new do |spec| |
6 | - spec.name = "syspro-ruby" | 8 | + spec.name = 'syspro-ruby' |
7 | spec.version = Syspro::VERSION | 9 | spec.version = Syspro::VERSION |
8 | - spec.authors = ["Isaac Lewis"] | ||
9 | - spec.email = ["isaac@ike.io"] | 10 | + spec.authors = ['Isaac Lewis'] |
11 | + spec.email = ['isaac@ike.io'] | ||
10 | 12 | ||
11 | - spec.summary = %q{SYSPRO 7 Api Ruby adapter} | ||
12 | - spec.license = "MIT" | 13 | + spec.summary = 'SYSPRO 7 Api Ruby adapter' |
14 | + spec.license = 'MIT' | ||
13 | 15 | ||
14 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' | 16 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' |
15 | # to allow pushing to a single host or delete this section to allow pushing to any host. | 17 | # to allow pushing to a single host or delete this section to allow pushing to any host. |
16 | if spec.respond_to?(:metadata) | 18 | if spec.respond_to?(:metadata) |
17 | - spec.metadata["allowed_push_host"] = "http://rubygems.org" | 19 | + spec.metadata['allowed_push_host'] = 'http://rubygems.org' |
18 | else | 20 | else |
19 | - raise "RubyGems 2.0 or newer is required to protect against " \ | ||
20 | - "public gem pushes." | 21 | + raise 'RubyGems 2.0 or newer is required to protect against ' \ |
22 | + 'public gem pushes.' | ||
21 | end | 23 | end |
24 | + spec.required_ruby_version = '>= 1.9.0' | ||
22 | 25 | ||
23 | - spec.files = `git ls-files -z`.split("\x0").reject do |f| | 26 | + spec.files = `git ls-files -z`.split("\x0").reject do |f| |
24 | f.match(%r{^(test|spec|features)/}) | 27 | f.match(%r{^(test|spec|features)/}) |
25 | end | 28 | end |
26 | - spec.bindir = "exe" | 29 | + spec.bindir = 'exe' |
27 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } | 30 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } |
28 | - spec.require_paths = ["lib"] | 31 | + spec.require_paths = ['lib'] |
29 | 32 | ||
30 | - spec.add_dependency("faraday", "~> 0.10") | 33 | + spec.add_dependency('faraday', '~> 0.10') |
34 | + spec.add_dependency('nokogiri', '~> 1.8.2') | ||
31 | 35 | ||
32 | - spec.add_development_dependency "bundler", "~> 1.16" | ||
33 | - spec.add_development_dependency "pry", "~> 0.11" | ||
34 | - spec.add_development_dependency "rake", "~> 10.0" | ||
35 | - spec.add_development_dependency "minitest", "~> 5.0" | 36 | + spec.add_development_dependency 'bundler', '~> 1.16' |
37 | + spec.add_development_dependency 'minitest', '~> 5.0' | ||
38 | + spec.add_development_dependency 'pry', '~> 0.11' | ||
39 | + spec.add_development_dependency 'rake', '~> 10.0' | ||
40 | + spec.add_development_dependency 'rubocop', '~> 0.54.0' | ||
41 | + spec.add_development_dependency 'webmock', '~> 3.3.0' | ||
42 | + spec.add_development_dependency 'minitest-vcr', '~> 1.4.0' | ||
36 | end | 43 | end |
1 | +--- | ||
2 | +http_interactions: | ||
3 | +- request: | ||
4 | + method: get | ||
5 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/getversion | ||
6 | + body: | ||
7 | + encoding: US-ASCII | ||
8 | + string: '' | ||
9 | + headers: | ||
10 | + User-Agent: | ||
11 | + - Syspro/7 RubyBindings/0.1.0 | ||
12 | + Content-Type: | ||
13 | + - application/x-www-form-urlencoded | ||
14 | + Accept-Encoding: | ||
15 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
16 | + Accept: | ||
17 | + - "*/*" | ||
18 | + response: | ||
19 | + status: | ||
20 | + code: 200 | ||
21 | + message: OK | ||
22 | + headers: | ||
23 | + Content-Length: | ||
24 | + - '7' | ||
25 | + Content-Type: | ||
26 | + - application/octet-stream | ||
27 | + Server: | ||
28 | + - Microsoft-HTTPAPI/2.0 | ||
29 | + Date: | ||
30 | + - Fri, 06 Apr 2018 19:23:43 GMT | ||
31 | + body: | ||
32 | + encoding: UTF-8 | ||
33 | + string: 7.0.0.6 | ||
34 | + http_version: | ||
35 | + recorded_at: Fri, 06 Apr 2018 19:23:42 GMT | ||
36 | +recorded_with: VCR 4.0.0 |
1 | +--- | ||
2 | +http_interactions: | ||
3 | +- request: | ||
4 | + method: get | ||
5 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/getversion | ||
6 | + body: | ||
7 | + encoding: US-ASCII | ||
8 | + string: '' | ||
9 | + headers: | ||
10 | + User-Agent: | ||
11 | + - Syspro/7 RubyBindings/0.1.0 | ||
12 | + Content-Type: | ||
13 | + - application/x-www-form-urlencoded | ||
14 | + Accept-Encoding: | ||
15 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
16 | + Accept: | ||
17 | + - "*/*" | ||
18 | + response: | ||
19 | + status: | ||
20 | + code: 200 | ||
21 | + message: OK | ||
22 | + headers: | ||
23 | + Content-Length: | ||
24 | + - '7' | ||
25 | + Content-Type: | ||
26 | + - application/octet-stream | ||
27 | + Server: | ||
28 | + - Microsoft-HTTPAPI/2.0 | ||
29 | + Date: | ||
30 | + - Fri, 06 Apr 2018 19:23:43 GMT | ||
31 | + body: | ||
32 | + encoding: UTF-8 | ||
33 | + string: 7.0.0.6 | ||
34 | + http_version: | ||
35 | + recorded_at: Fri, 06 Apr 2018 19:23:42 GMT | ||
36 | +recorded_with: VCR 4.0.0 |
1 | +--- | ||
2 | +http_interactions: | ||
3 | +- request: | ||
4 | + method: get | ||
5 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/logoff?UserId=1BB5B3050954BB459A5D034DB5CC386980 | ||
6 | + body: | ||
7 | + encoding: US-ASCII | ||
8 | + string: '' | ||
9 | + headers: | ||
10 | + User-Agent: | ||
11 | + - Syspro/7 RubyBindings/0.1.0 | ||
12 | + Content-Type: | ||
13 | + - application/x-www-form-urlencoded | ||
14 | + Accept-Encoding: | ||
15 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
16 | + Accept: | ||
17 | + - "*/*" | ||
18 | + response: | ||
19 | + status: | ||
20 | + code: 200 | ||
21 | + message: OK | ||
22 | + headers: | ||
23 | + Content-Length: | ||
24 | + - '72' | ||
25 | + Content-Type: | ||
26 | + - application/octet-stream | ||
27 | + Server: | ||
28 | + - Microsoft-HTTPAPI/2.0 | ||
29 | + Date: | ||
30 | + - Fri, 06 Apr 2018 19:22:53 GMT | ||
31 | + body: | ||
32 | + encoding: UTF-8 | ||
33 | + string: 'ERROR: Unable to read the SYSPRO base directory registry string BaseDir8' | ||
34 | + http_version: | ||
35 | + recorded_at: Fri, 06 Apr 2018 19:22:52 GMT | ||
36 | +recorded_with: VCR 4.0.0 |
1 | +--- | ||
2 | +http_interactions: | ||
3 | +- request: | ||
4 | + method: get | ||
5 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/logon?CompanyId=L&CompanyPassword=&Operator=wland&OperatorPassword=piperita2016 | ||
6 | + body: | ||
7 | + encoding: US-ASCII | ||
8 | + string: '' | ||
9 | + headers: | ||
10 | + User-Agent: | ||
11 | + - Syspro/7 RubyBindings/0.1.0 | ||
12 | + Content-Type: | ||
13 | + - application/x-www-form-urlencoded | ||
14 | + Accept-Encoding: | ||
15 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
16 | + Accept: | ||
17 | + - "*/*" | ||
18 | + response: | ||
19 | + status: | ||
20 | + code: 200 | ||
21 | + message: OK | ||
22 | + headers: | ||
23 | + Content-Length: | ||
24 | + - '36' | ||
25 | + Content-Type: | ||
26 | + - application/octet-stream | ||
27 | + Server: | ||
28 | + - Microsoft-HTTPAPI/2.0 | ||
29 | + Date: | ||
30 | + - Fri, 06 Apr 2018 19:23:52 GMT | ||
31 | + body: | ||
32 | + encoding: UTF-8 | ||
33 | + string: 'EC3098D6E284FB44ADF10671B3F06FCA00 ' | ||
34 | + http_version: | ||
35 | + recorded_at: Fri, 06 Apr 2018 19:23:51 GMT | ||
36 | +recorded_with: VCR 4.0.0 |
1 | +--- | ||
2 | +http_interactions: | ||
3 | +- request: | ||
4 | + method: get | ||
5 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/logon?CompanyId=L&CompanyPassword=&Operator=wland&OperatorPassword=piperita2016 | ||
6 | + body: | ||
7 | + encoding: US-ASCII | ||
8 | + string: '' | ||
9 | + headers: | ||
10 | + User-Agent: | ||
11 | + - Syspro/7 RubyBindings/0.1.0 | ||
12 | + Content-Type: | ||
13 | + - application/x-www-form-urlencoded | ||
14 | + Accept-Encoding: | ||
15 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
16 | + Accept: | ||
17 | + - "*/*" | ||
18 | + response: | ||
19 | + status: | ||
20 | + code: 200 | ||
21 | + message: OK | ||
22 | + headers: | ||
23 | + Content-Length: | ||
24 | + - '36' | ||
25 | + Content-Type: | ||
26 | + - application/octet-stream | ||
27 | + Server: | ||
28 | + - Microsoft-HTTPAPI/2.0 | ||
29 | + Date: | ||
30 | + - Fri, 06 Apr 2018 19:23:03 GMT | ||
31 | + body: | ||
32 | + encoding: UTF-8 | ||
33 | + string: '64C41E1DEB73024CA660211DE643705700 ' | ||
34 | + http_version: | ||
35 | + recorded_at: Fri, 06 Apr 2018 19:23:01 GMT | ||
36 | +- request: | ||
37 | + method: get | ||
38 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/Query/Browse?UserId=64C41E1DEB73024CA660211DE643705700%20%20&XmlIn=%3C?xml%20version=%221.0%22%20encoding=%22Windows-1252%22?%3E%0A%3CBrowse%20xmlns:xsd=%22http://www.w3.org/2001/XMLSchema-instance%22%20xsd:noNamespaceSchemaLocation=%22COMBRW.XSD%22%3E%0A%20%20%3CBrowseName%3EInvMaster%3C/BrowseName%3E%0A%20%20%3CStartAtKey/%3E%0A%20%20%3CStartCondition%3E%3C/StartCondition%3E%0A%20%20%3CReturnRows%3E5%3C/ReturnRows%3E%0A%20%20%0A%20%20%3CBrowseDetails%3E%0A%20%20%20%20%3CTableName%3EInvMaster%3C/TableName%3E%0A%20%20%20%20%3CTitle%3EStockCodes%3C/Title%3E%0A%20%20%20%20%0A%20%20%20%20%20%20%3CColumn%3E%0A%20%20%20%20%20%20%20%20%3CColumnName%3EStockCode%3C/ColumnName%3E%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%3C/Column%3E%0A%20%20%20%20%0A%20%20%3C/BrowseDetails%3E%0A%3C/Browse%3E%0A%0A | ||
39 | + body: | ||
40 | + encoding: US-ASCII | ||
41 | + string: '' | ||
42 | + headers: | ||
43 | + User-Agent: | ||
44 | + - Syspro/7 RubyBindings/0.1.0 | ||
45 | + Content-Type: | ||
46 | + - application/x-www-form-urlencoded | ||
47 | + Accept-Encoding: | ||
48 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
49 | + Accept: | ||
50 | + - "*/*" | ||
51 | + response: | ||
52 | + status: | ||
53 | + code: 200 | ||
54 | + message: OK | ||
55 | + headers: | ||
56 | + Content-Length: | ||
57 | + - '944' | ||
58 | + Content-Type: | ||
59 | + - application/octet-stream | ||
60 | + Server: | ||
61 | + - Microsoft-HTTPAPI/2.0 | ||
62 | + Date: | ||
63 | + - Fri, 06 Apr 2018 19:23:07 GMT | ||
64 | + body: | ||
65 | + encoding: UTF-8 | ||
66 | + string: "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<InvMaster Language='05' | ||
67 | + Language2='EN' CssStyle='' DecFormat='1' DateFormat='01' Role='01' Version='7.0.036' | ||
68 | + OperatorPrimaryRole=' '>\n<Title>StockCodes</Title>\n<Row>\n<StockCode>\n<Value>02</Value>\n<DataType>AlphaNumeric</DataType>\n</StockCode>\n</Row>\n<Row>\n<StockCode>\n<Value>021</Value>\n<DataType>AlphaNumeric</DataType>\n</StockCode>\n</Row>\n<Row>\n<StockCode>\n<Value>0214011IFF</Value>\n<DataType>AlphaNumeric</DataType>\n</StockCode>\n</Row>\n<Row>\n<StockCode>\n<Value>022</Value>\n<DataType>AlphaNumeric</DataType>\n</StockCode>\n</Row>\n<Row>\n<StockCode>\n<Value>023</Value>\n<DataType>AlphaNumeric</DataType>\n</StockCode>\n</Row>\n<NextPrevKey>\n<PrevKey>02</PrevKey>\n<NextKey>023</NextKey>\n<Fwd>True</Fwd>\n<Back>False</Back>\n</NextPrevKey>\n<HeaderDetails>\n<Header>Stock | ||
69 | + code</Header>\n<Key>StockCode</Key>\n<KeyDescription>Stock code</KeyDescription>\n<Table>InvMaster</Table>\n</HeaderDetails>\n</InvMaster>\n " | ||
70 | + http_version: | ||
71 | + recorded_at: Fri, 06 Apr 2018 19:23:06 GMT | ||
72 | +recorded_with: VCR 4.0.0 |
1 | +--- | ||
2 | +http_interactions: | ||
3 | +- request: | ||
4 | + method: get | ||
5 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/logon?CompanyId=L&CompanyPassword=&Operator=wland&OperatorPassword=piperita2016 | ||
6 | + body: | ||
7 | + encoding: US-ASCII | ||
8 | + string: '' | ||
9 | + headers: | ||
10 | + User-Agent: | ||
11 | + - Syspro/7 RubyBindings/0.1.0 | ||
12 | + Content-Type: | ||
13 | + - application/x-www-form-urlencoded | ||
14 | + Accept-Encoding: | ||
15 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
16 | + Accept: | ||
17 | + - "*/*" | ||
18 | + response: | ||
19 | + status: | ||
20 | + code: 200 | ||
21 | + message: OK | ||
22 | + headers: | ||
23 | + Content-Length: | ||
24 | + - '36' | ||
25 | + Content-Type: | ||
26 | + - application/octet-stream | ||
27 | + Server: | ||
28 | + - Microsoft-HTTPAPI/2.0 | ||
29 | + Date: | ||
30 | + - Fri, 06 Apr 2018 19:23:16 GMT | ||
31 | + body: | ||
32 | + encoding: UTF-8 | ||
33 | + string: '5B21680F424424498B7CE7CCDA98B41700 ' | ||
34 | + http_version: | ||
35 | + recorded_at: Fri, 06 Apr 2018 19:23:15 GMT | ||
36 | +- request: | ||
37 | + method: get | ||
38 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/Query/Fetch?UserId=5B21680F424424498B7CE7CCDA98B41700%20%20&XmlIn=%3C?xml%20version=%221.0%22%20encoding=%22Windows-1252%22?%3E%0A%3CFetch%20xmlns:xsd=%22http://www.w3.org/2001/XMLSchema-instance%22%20xsd:noNamespaceSchemaLocation=%22COMFCH.XSD%22%3E%0A%20%20%3CTableName%3EInvMaster%3C/TableName%3E%0A%20%20%3CKey%3E02%3C/Key%3E%0A%20%20%0A%20%20%3CFullKeyProvided%3EY%3C/FullKeyProvided%3E%0A%20%20%3CDefaultType%3E%3C/DefaultType%3E%0A%20%20%3CEspressoFetch%3EN%3C/EspressoFetch%3E%0A%3C/Fetch%3E%0A%0A | ||
39 | + body: | ||
40 | + encoding: US-ASCII | ||
41 | + string: '' | ||
42 | + headers: | ||
43 | + User-Agent: | ||
44 | + - Syspro/7 RubyBindings/0.1.0 | ||
45 | + Content-Type: | ||
46 | + - application/x-www-form-urlencoded | ||
47 | + Accept-Encoding: | ||
48 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
49 | + Accept: | ||
50 | + - "*/*" | ||
51 | + response: | ||
52 | + status: | ||
53 | + code: 200 | ||
54 | + message: OK | ||
55 | + headers: | ||
56 | + Content-Length: | ||
57 | + - '3911' | ||
58 | + Content-Type: | ||
59 | + - application/octet-stream | ||
60 | + Server: | ||
61 | + - Microsoft-HTTPAPI/2.0 | ||
62 | + Date: | ||
63 | + - Fri, 06 Apr 2018 19:23:26 GMT | ||
64 | + body: | ||
65 | + encoding: UTF-8 | ||
66 | + string: "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<InvMaster Language='05' | ||
67 | + Language2='EN' CssStyle='' DecFormat='1' DateFormat='01' Role='01' Version='7.0.035' | ||
68 | + OperatorPrimaryRole=' '>\n<StockCode>02</StockCode>\n<Description>STR</Description>\n<LongDesc>SPEARMINT | ||
69 | + TERPENES</LongDesc>\n<AlternateKey1/>\n<AlternateKey2/>\n<EccUser/>\n<StockUom>LB</StockUom>\n<AlternateUom>KG</AlternateUom>\n<OtherUom>DR</OtherUom>\n<ConvFactAltUom> | ||
70 | + \ 2.204620</ConvFactAltUom>\n<ConvMulDiv>M</ConvMulDiv>\n<ConvFactOthUom> | ||
71 | + \ 400.000000</ConvFactOthUom>\n<MulDiv>M</MulDiv>\n<Mass> 1.000000</Mass>\n<Volume> | ||
72 | + \ 0.000000</Volume>\n<Decimals>3</Decimals>\n<PriceCategory>A</PriceCategory>\n<PriceMethod>C</PriceMethod>\n<Supplier/>\n<CycleCount> | ||
73 | + 0</CycleCount>\n<ProductClass>STRP</ProductClass>\n<TaxCode>A</TaxCode>\n<OtherTaxCode/>\n<ListPriceCode>A</ListPriceCode>\n<SerialMethod>N</SerialMethod>\n<InterfaceFlag>Y</InterfaceFlag>\n<KitType>N</KitType>\n<LowLevelCode> | ||
74 | + 0</LowLevelCode>\n<Buyer/>\n<Planner/>\n<TraceableType>T</TraceableType>\n<MpsFlag>N</MpsFlag>\n<BulkIssueFlag>N</BulkIssueFlag>\n<AbcClass/>\n<LeadTime> | ||
75 | + \ 0</LeadTime>\n<StockMovementReq>Y</StockMovementReq>\n<ClearingFlag>N</ClearingFlag>\n<SupercessionDate>0000-00-00</SupercessionDate>\n<AbcAnalysisReq>Y</AbcAnalysisReq>\n<AbcCostingReq>N</AbcCostingReq>\n<CostUom>LB</CostUom>\n<MinPricePct> | ||
76 | + \ 0.00</MinPricePct>\n<LabourCost> 0.00000</LabourCost>\n<MaterialCost> | ||
77 | + \ 0.00000</MaterialCost>\n<FixOverhead> 0.00000</FixOverhead>\n<VariableOverhead> | ||
78 | + \ 0.00000</VariableOverhead>\n<PartCategory>B</PartCategory>\n<DrawOfficeNum/>\n<WarehouseToUse>H1</WarehouseToUse>\n<BuyingRule>A</BuyingRule>\n<SpecificGravity> | ||
79 | + 0.0000</SpecificGravity>\n<ImplosionNum> 0</ImplosionNum>\n<Ebq> 400.000000</Ebq>\n<ComponentCount> | ||
80 | + \ 0</ComponentCount>\n<FixTimePeriod> 1</FixTimePeriod>\n<PanSize> 0.000000</PanSize>\n<DockToStock> | ||
81 | + \ 0</DockToStock>\n<OutputMassFlag>F</OutputMassFlag>\n<ShelfLife> | ||
82 | + \ 0</ShelfLife>\n<Version/>\n<Release/>\n<DemandTimeFence> 0</DemandTimeFence>\n<MakeToOrderFlag>N</MakeToOrderFlag>\n<ManufLeadTime> | ||
83 | + \ 0</ManufLeadTime>\n<GrossReqRule>I</GrossReqRule>\n<PercentageYield>100</PercentageYield>\n<AbcPreProd> | ||
84 | + \ 0.00000</AbcPreProd>\n<AbcManufacturing> 0.00000</AbcManufacturing>\n<AbcSales> | ||
85 | + \ 0.00000</AbcSales>\n<AbcCumPreProd> 0.00000</AbcCumPreProd>\n<AbcCumManuf> | ||
86 | + \ 0.00000</AbcCumManuf>\n<WipCtlGlCode/>\n<ResourceCode/>\n<GstTaxCode>A</GstTaxCode>\n<PrcInclGst>N</PrcInclGst>\n<SerEntryAtSale/>\n<StpSelection/>\n<UserField1/>\n<UserField2> | ||
87 | + \ 0.00000</UserField2>\n<UserField3/>\n<UserField4/>\n<UserField5/>\n<TariffCode/>\n<SupplementaryUnit>N</SupplementaryUnit>\n<EbqPan>E</EbqPan>\n<StdLandedCost> | ||
88 | + \ 0.00000</StdLandedCost>\n<LctRequired>N</LctRequired>\n<StdLctRoute/>\n<IssMultLotsFlag>Y</IssMultLotsFlag>\n<InclInStrValid>Y</InclInStrValid>\n<StdLabCostsBill> | ||
89 | + \ 0.00000</StdLabCostsBill>\n<PhantomIfComp/>\n<CountryOfOrigin/>\n<StockOnHold/>\n<StockOnHoldReason/>\n<EccFlag>N</EccFlag>\n<StockAndAltUm>N</StockAndAltUm>\n<AltUnitChar>0</AltUnitChar>\n<JobsOnHold/>\n<JobHoldAllocs/>\n<PurchOnHold/>\n<SalesOnHold/>\n<MaintOnHold/>\n<BatchBill>N</BatchBill>\n<BlanketPoExists/>\n<CallOffBpoExists/>\n<DistWarehouseToUse/>\n<JobClassification/>\n<SubContractCost> | ||
90 | + \ 0.00000</SubContractCost>\n<DateStkAdded>2005-08-26</DateStkAdded>\n<InspectionFlag/>\n<SerialPrefix/>\n<SerialSuffix/>\n<ReturnableItem/>\n<ProductGroup/>\n<PriceType/>\n<Basis/>\n<ManualCostFlag/>\n<ManufactureUom>LB</ManufactureUom>\n<ConvFactMuM> | ||
91 | + \ 1.000000</ConvFactMuM>\n<ManMulDiv>M</ManMulDiv>\n<LookAheadWin> 0</LookAheadWin>\n<LoadingFactor> | ||
92 | + \ 0.000</LoadingFactor>\n<SupplUnitCode/>\n<StorageSecurity/>\n<StorageHazard/>\n<StorageCondition/>\n<ProductShelfLife> | ||
93 | + \ 0</ProductShelfLife>\n<InternalShelfLife> 0</InternalShelfLife>\n<AltMethodFlag/>\n<AltSisoFlag/>\n<AltReductionFlag/>\n<WithTaxExpenseType/>\n</InvMaster>\n " | ||
94 | + http_version: | ||
95 | + recorded_at: Fri, 06 Apr 2018 19:23:24 GMT | ||
96 | +recorded_with: VCR 4.0.0 |
1 | +--- | ||
2 | +http_interactions: | ||
3 | +- request: | ||
4 | + method: get | ||
5 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/logon?CompanyId=L&CompanyPassword=&Operator=wland&OperatorPassword=piperita2016 | ||
6 | + body: | ||
7 | + encoding: US-ASCII | ||
8 | + string: '' | ||
9 | + headers: | ||
10 | + User-Agent: | ||
11 | + - Syspro/7 RubyBindings/0.1.0 | ||
12 | + Content-Type: | ||
13 | + - application/x-www-form-urlencoded | ||
14 | + Accept-Encoding: | ||
15 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
16 | + Accept: | ||
17 | + - "*/*" | ||
18 | + response: | ||
19 | + status: | ||
20 | + code: 200 | ||
21 | + message: OK | ||
22 | + headers: | ||
23 | + Content-Length: | ||
24 | + - '36' | ||
25 | + Content-Type: | ||
26 | + - application/octet-stream | ||
27 | + Server: | ||
28 | + - Microsoft-HTTPAPI/2.0 | ||
29 | + Date: | ||
30 | + - Fri, 06 Apr 2018 19:23:35 GMT | ||
31 | + body: | ||
32 | + encoding: UTF-8 | ||
33 | + string: '5810EEA000F1F04BA915BAF98CA700EE00 ' | ||
34 | + http_version: | ||
35 | + recorded_at: Fri, 06 Apr 2018 19:23:33 GMT | ||
36 | +- request: | ||
37 | + method: get | ||
38 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/Query/Query?BusinessObject=COMFND&UserId=5810EEA000F1F04BA915BAF98CA700EE00%20%20&XmlIn=%3C?xml%20version=%221.0%22%20encoding=%22Windows-1252%22?%3E%0A%3CQuery%20xmlns:xsd=%22http://www.w3.org/2001/XMLSchema-instance%22%20xsd:noNamespaceSchemaLocation=%22COMFND.XSD%22%3E%0A%20%20%3CTableName%3EInvMaster%3C/TableName%3E%0A%20%20%3CReturnRows%3E5%3C/ReturnRows%3E%0A%20%20%3CColumns%3E%0A%20%20%20%20%0A%20%20%20%20%20%20%3CColumn%3EStockCode%3C/Column%3E%0A%20%20%20%20%0A%20%20%3C/Columns%3E%0A%20%20%0A%20%20%20%20%3CWhere%3E%0A%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%3CExpression%3E%0A%20%20%20%20%20%20%20%20%20%20%3COpenBracket%3E(%3C/OpenBracket%3E%0A%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CAndOr%3EAnd%3C/AndOr%3E%0A%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%3CColumn%3EStockCode%3C/Column%3E%0A%20%20%20%20%20%20%20%20%20%20%3CCondition%3EEQ%3C/Condition%3E%0A%20%20%20%20%20%20%20%20%20%20%3CValue%3E02%3C/Value%3E%0A%20%20%20%20%20%20%20%20%20%20%3CCloseBracket%3E)%3C/CloseBracket%3E%0A%20%20%20%20%20%20%20%20%3C/Expression%3E%0A%20%20%20%20%20%20%0A%20%20%20%20%3C/Where%3E%0A%20%20%0A%20%20%3COrderBy%3E%0A%20%20%20%20%3CColumn%3EStockCode%3C/Column%3E%0A%20%20%3C/OrderBy%3E%0A%3C/Query%3E%0A | ||
39 | + body: | ||
40 | + encoding: US-ASCII | ||
41 | + string: '' | ||
42 | + headers: | ||
43 | + User-Agent: | ||
44 | + - Syspro/7 RubyBindings/0.1.0 | ||
45 | + Content-Type: | ||
46 | + - application/x-www-form-urlencoded | ||
47 | + Accept-Encoding: | ||
48 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
49 | + Accept: | ||
50 | + - "*/*" | ||
51 | + response: | ||
52 | + status: | ||
53 | + code: 200 | ||
54 | + message: OK | ||
55 | + headers: | ||
56 | + Content-Length: | ||
57 | + - '436' | ||
58 | + Content-Type: | ||
59 | + - application/octet-stream | ||
60 | + Server: | ||
61 | + - Microsoft-HTTPAPI/2.0 | ||
62 | + Date: | ||
63 | + - Fri, 06 Apr 2018 19:23:43 GMT | ||
64 | + body: | ||
65 | + encoding: UTF-8 | ||
66 | + string: "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<InvMaster Language='05' | ||
67 | + Language2='EN' CssStyle='' DecFormat='1' DateFormat='01' Role='01' Version='7.0.048' | ||
68 | + OperatorPrimaryRole=' '>\n<HeaderDetails>\n<TableName>InvMaster</TableName>\n<Columns>\n<Column>StockCode</Column>\n</Columns>\n<OrderBy>\n<Column>StockCode</Column>\n</OrderBy>\n</HeaderDetails>\n<Row>\n<StockCode>02</StockCode>\n</Row>\n<RowsReturned> | ||
69 | + \ 1</RowsReturned>\n</InvMaster>\n " | ||
70 | + http_version: | ||
71 | + recorded_at: Fri, 06 Apr 2018 19:23:41 GMT | ||
72 | +recorded_with: VCR 4.0.0 |
1 | +--- | ||
2 | +http_interactions: | ||
3 | +- request: | ||
4 | + method: get | ||
5 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/logon?CompanyId=L&CompanyPassword=&Operator=wland&OperatorPassword=piperita2016 | ||
6 | + body: | ||
7 | + encoding: US-ASCII | ||
8 | + string: '' | ||
9 | + headers: | ||
10 | + User-Agent: | ||
11 | + - Syspro/7 RubyBindings/0.1.0 | ||
12 | + Content-Type: | ||
13 | + - application/x-www-form-urlencoded | ||
14 | + Accept-Encoding: | ||
15 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
16 | + Accept: | ||
17 | + - "*/*" | ||
18 | + response: | ||
19 | + status: | ||
20 | + code: 200 | ||
21 | + message: OK | ||
22 | + headers: | ||
23 | + Content-Length: | ||
24 | + - '36' | ||
25 | + Content-Type: | ||
26 | + - application/octet-stream | ||
27 | + Server: | ||
28 | + - Microsoft-HTTPAPI/2.0 | ||
29 | + Date: | ||
30 | + - Fri, 06 Apr 2018 19:22:53 GMT | ||
31 | + body: | ||
32 | + encoding: UTF-8 | ||
33 | + string: '989D81EB0B184A499E7AC2E28724EE9000 ' | ||
34 | + http_version: | ||
35 | + recorded_at: Fri, 06 Apr 2018 19:22:52 GMT | ||
36 | +- request: | ||
37 | + method: get | ||
38 | + uri: http://syspro.wildlandlabs.com:90/SYSPROWCFService/Rest/logoff?UserId=989D81EB0B184A499E7AC2E28724EE9000%20%20 | ||
39 | + body: | ||
40 | + encoding: US-ASCII | ||
41 | + string: '' | ||
42 | + headers: | ||
43 | + User-Agent: | ||
44 | + - Syspro/7 RubyBindings/0.1.0 | ||
45 | + Content-Type: | ||
46 | + - application/x-www-form-urlencoded | ||
47 | + Accept-Encoding: | ||
48 | + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 | ||
49 | + Accept: | ||
50 | + - "*/*" | ||
51 | + response: | ||
52 | + status: | ||
53 | + code: 200 | ||
54 | + message: OK | ||
55 | + headers: | ||
56 | + Content-Length: | ||
57 | + - '1' | ||
58 | + Content-Type: | ||
59 | + - application/octet-stream | ||
60 | + Server: | ||
61 | + - Microsoft-HTTPAPI/2.0 | ||
62 | + Date: | ||
63 | + - Fri, 06 Apr 2018 19:22:53 GMT | ||
64 | + body: | ||
65 | + encoding: UTF-8 | ||
66 | + string: '0' | ||
67 | + http_version: | ||
68 | + recorded_at: Fri, 06 Apr 2018 19:22:52 GMT | ||
69 | +recorded_with: VCR 4.0.0 |
test/client_test.rb
1 | -require "test_helper" | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +require 'test_helper' | ||
2 | 4 | ||
3 | class SysproClientTest < Minitest::Test | 5 | class SysproClientTest < Minitest::Test |
6 | + extend Minitest::Spec::DSL | ||
7 | + before { VCR.insert_cassette name } | ||
8 | + after { VCR.eject_cassette } | ||
9 | + | ||
10 | + let(:client) { ::Syspro::SysproClient.new } | ||
11 | + | ||
4 | def test_get_syspro_version | 12 | def test_get_syspro_version |
5 | - client = ::Syspro::SysproClient.new | ||
6 | - assert_match (/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/), client.get_syspro_version.version | 13 | + assert_match( |
14 | + /(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/, | ||
15 | + client.get_syspro_version.version | ||
16 | + ) | ||
7 | end | 17 | end |
8 | 18 | ||
9 | def test_client_block_execution | 19 | def test_client_block_execution |
10 | - client = ::Syspro::SysproClient.new | ||
11 | - | ||
12 | - version, resp = client.request { | 20 | + version, resp = client.request do |
13 | Syspro::GetVersion.get_version | 21 | Syspro::GetVersion.get_version |
14 | - } | 22 | + end |
15 | 23 | ||
16 | - assert_match version.version, resp.http_body | ||
17 | - assert_match (/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/), version.version | 24 | + assert_match(version.version, resp.http_body) |
25 | + assert_match(/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/, version.version) | ||
18 | end | 26 | end |
19 | end | 27 | end |
test/logoff_test.rb
1 | -require "test_helper" | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +require 'test_helper' | ||
2 | 4 | ||
3 | class LogoffTest < Minitest::Test | 5 | class LogoffTest < Minitest::Test |
4 | - def test_successful_logoff | ||
5 | - username = "wland" | ||
6 | - password = "piperita2016" | ||
7 | - company = "L" | ||
8 | - company_password = "" | 6 | + extend Minitest::Spec::DSL |
7 | + before { VCR.insert_cassette name } | ||
8 | + after { VCR.eject_cassette } | ||
9 | + | ||
10 | + let(:username) { 'wland' } | ||
11 | + let(:password) { 'piperita2016' } | ||
12 | + let(:company) { 'L' } | ||
13 | + let(:company_password) { '' } | ||
9 | 14 | ||
15 | + def test_successful_logoff | ||
10 | uid = Syspro::Logon.logon(username, password, company, company_password) | 16 | uid = Syspro::Logon.logon(username, password, company, company_password) |
11 | assert_equal true, Syspro::Logoff.logoff(uid.guid) | 17 | assert_equal true, Syspro::Logoff.logoff(uid.guid) |
12 | end | 18 | end |
13 | 19 | ||
14 | def test_logoff_error | 20 | def test_logoff_error |
15 | - assert_kind_of String, Syspro::Logoff.logoff('1BB5B3050954BB459A5D034DB5CC386980') | 21 | + assert_kind_of( |
22 | + String, | ||
23 | + Syspro::Logoff.logoff('1BB5B3050954BB459A5D034DB5CC386980') | ||
24 | + ) | ||
16 | end | 25 | end |
17 | end | 26 | end |
18 | - |
test/logon_test.rb
1 | -require "test_helper" | 1 | +# frozen_string_literal: true |
2 | + | ||
3 | +require 'test_helper' | ||
2 | 4 | ||
3 | class LogonTest < Minitest::Test | 5 | class LogonTest < Minitest::Test |
4 | - def test_logon | ||
5 | - username = "wland" | ||
6 | - password = "piperita2016" | ||
7 | - company = "L" | ||
8 | - company_password = "" | ||
9 | - client = ::Syspro::SysproClient.new | 6 | + extend Minitest::Spec::DSL |
7 | + before { VCR.insert_cassette name } | ||
8 | + after { VCR.eject_cassette } | ||
9 | + | ||
10 | + let(:username) { 'wland' } | ||
11 | + let(:password) { 'piperita2016' } | ||
12 | + let(:company) { 'L' } | ||
13 | + let(:company_password) { '' } | ||
10 | 14 | ||
11 | - assert_match (/([A-Z0-9]{33})\w/), client.logon(username, password, company, company_password).guid | 15 | + def test_logon |
16 | + assert_match( | ||
17 | + /([A-Z0-9]{33})\w/, | ||
18 | + ::Syspro::SysproClient.new.logon( | ||
19 | + username, | ||
20 | + password, | ||
21 | + company, | ||
22 | + company_password | ||
23 | + ).guid | ||
24 | + ) | ||
12 | end | 25 | end |
13 | end | 26 | end |
14 | - |
1 | +# frozen_string_literal: true | ||
2 | + | ||
3 | +require 'test_helper' | ||
4 | + | ||
5 | +class QueryTest < Minitest::Test | ||
6 | + extend Minitest::Spec::DSL | ||
7 | + before { VCR.insert_cassette name } | ||
8 | + after { VCR.eject_cassette } | ||
9 | + | ||
10 | + let(:username) { 'wland' } | ||
11 | + let(:password) { 'piperita2016' } | ||
12 | + let(:company) { 'L' } | ||
13 | + let(:company_password) { '' } | ||
14 | + let(:user_id) do | ||
15 | + Syspro::Logon.logon(username, password, company, company_password) | ||
16 | + end | ||
17 | + | ||
18 | + def test_query_browse # rubocop:disable Metrics/MethodLength | ||
19 | + combrw = Syspro::BusinessObjects::ComBrw.new | ||
20 | + combrw.browse_name = 'InvMaster' | ||
21 | + combrw.start_condition = '' | ||
22 | + combrw.return_rows = 5 | ||
23 | + combrw.filters = [] | ||
24 | + combrw.table_name = 'InvMaster' | ||
25 | + combrw.title = 'StockCodes' | ||
26 | + combrw.columns = [ | ||
27 | + { name: 'StockCode' } | ||
28 | + ] | ||
29 | + | ||
30 | + browse_result = combrw.call(user_id.guid) | ||
31 | + | ||
32 | + refute_nil browse_result | ||
33 | + end | ||
34 | + | ||
35 | + def test_query_query # rubocop:disable Metrics/MethodLength | ||
36 | + comfnd = Syspro::BusinessObjects::ComFnd.new | ||
37 | + comfnd.table_name = 'InvMaster' | ||
38 | + comfnd.return_rows = 5 | ||
39 | + comfnd.columns = [ | ||
40 | + { | ||
41 | + name: 'StockCode' | ||
42 | + } | ||
43 | + ] | ||
44 | + comfnd.expressions = [ | ||
45 | + { | ||
46 | + andor: 'And', | ||
47 | + column: 'StockCode', | ||
48 | + condition: 'EQ', | ||
49 | + value: '02' | ||
50 | + } | ||
51 | + ] | ||
52 | + comfnd.order_by = 'StockCode' | ||
53 | + | ||
54 | + query_result = comfnd.call(user_id.guid) | ||
55 | + | ||
56 | + refute_nil query_result | ||
57 | + end | ||
58 | + | ||
59 | + def test_query_fetch | ||
60 | + comfch = Syspro::BusinessObjects::ComFch.new | ||
61 | + comfch.table_name = 'InvMaster' | ||
62 | + comfch.key = '02' | ||
63 | + comfch.optional_keys = [] | ||
64 | + comfch.full_key_provided = false | ||
65 | + comfch.default_type = '' | ||
66 | + comfch.espresso_fetch = true | ||
67 | + | ||
68 | + fetch_result = comfch.call(user_id.guid) | ||
69 | + | ||
70 | + refute_nil fetch_result | ||
71 | + end | ||
72 | +end |
test/syspro_test.rb
test/test_helper.rb
1 | -$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) | ||
2 | -require "syspro" | 1 | +# frozen_string_literal: true |
3 | 2 | ||
4 | -require "pry" | ||
5 | -require "minitest/autorun" | 3 | +$LOAD_PATH.unshift File.expand_path('../lib', __dir__) |
4 | +require 'syspro' | ||
5 | + | ||
6 | +require 'pry' | ||
7 | +require 'minitest/autorun' | ||
8 | +require 'minitest-vcr' | ||
9 | +require 'webmock' | ||
10 | + | ||
11 | +VCR.configure do |c| | ||
12 | + c.cassette_library_dir = 'test/cassettes' | ||
13 | + c.hook_into :webmock | ||
14 | + # TODO: change passwords and move them to ENV | ||
15 | + # c.filter_sensitive_data() { ENV[] } | ||
16 | +end | ||
17 | + | ||
18 | +MinitestVcr::Spec.configure! |