Commit 0c0af54a8bd446733ec29ed87509d6c12b68d578

Authored by Isaac Lewis
1 parent eef01045

error handling; cleanup; rename to `syspro-ruby`

@@ -2,5 +2,4 @@ source "https://rubygems.org" @@ -2,5 +2,4 @@ source "https://rubygems.org"
2 2
3 git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } 3 git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4 4
5 -# Specify your gem's dependencies in syspro.gemspec  
6 gemspec 5 gemspec
1 -# Syspro 1 +# syspro-ruby
2 2
3 -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/syspro`. To experiment with that code, run `bin/console` for an interactive prompt.  
4 -  
5 -TODO: Delete this and the text above, and describe your gem 3 +syspro-ruby is an adapter gem to connect to SYSPRO 7 ERP installations. You can use this gem to connect to the SYSPRO 7 WCF Service and build Ruby applications on top of your SYSPRO data.
6 4
7 ## Installation 5 ## Installation
8 6
@@ -22,7 +20,57 @@ Or install it yourself as: @@ -22,7 +20,57 @@ Or install it yourself as:
22 20
23 ## Usage 21 ## Usage
24 22
25 -TODO: Write usage instructions here 23 +### Utilities
  24 +
  25 +#### Logon
  26 +
  27 +```rb
  28 +user_id = Syspro::Logon.logon(username, password, company_id, company_password)
  29 +```
  30 +`user_id` will be a `UserId` object that contains the `guid` supplied by SYSPRO. You will use this guid to make further requests to SYSPRO.
  31 +
  32 +#### GetUserProfile
  33 +
  34 +```rb
  35 +user_profile = Syspro::GetUserProfile.get_user_profile(guid)
  36 +```
  37 +`user_profile` will be a `UserProfile` object that contains the following:
  38 + - `company_name`
  39 + - `operator_code`
  40 + - `operator_group`
  41 + - `operator_email_address`
  42 + - `operator_location`
  43 + - `operator_language_code`
  44 + - `system_language`
  45 + - `accounting_date`
  46 + - `company_date`
  47 + - `default_ar_branch`
  48 + - `default_ap_branch`
  49 + - `default_bank`
  50 + - `default_warehouse`
  51 + - `default_customer`
  52 + - `system_site_id`
  53 + - `system_nationality_code`
  54 + - `local_currency_code`
  55 + - `currency_description`
  56 + - `default_requisition_user`
  57 + - `xml_to_html_transform`
  58 + - `css_style`
  59 + - `css_suffix`
  60 + - `decimal_format`
  61 + - `date_format`
  62 + - `functional_role`
  63 + - `database_type`
  64 + - `syspro_version`
  65 + - `enet_version`
  66 + - `syspro_server_bit_width`
  67 +
  68 +#### Logoff
  69 +
  70 +```rb
  71 +logged_off = Syspro::Logoff.logoff(guid)
  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.
26 74
27 ## Development 75 ## Development
28 76
@@ -32,7 +80,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To @@ -32,7 +80,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32 80
33 ## Contributing 81 ## Contributing
34 82
35 -Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/syspro. 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. 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.
36 84
37 ## License 85 ## License
38 86
@@ -40,4 +88,4 @@ The gem is available as open source under the terms of the [MIT License](https:/ @@ -40,4 +88,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40 88
41 ## Code of Conduct 89 ## Code of Conduct
42 90
43 -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/[USERNAME]/syspro/blob/master/CODE_OF_CONDUCT.md). 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).
@@ -2,13 +2,6 @@ @@ -2,13 +2,6 @@
2 2
3 require "bundler/setup" 3 require "bundler/setup"
4 require "syspro" 4 require "syspro"
  5 +require "pry"
5 6
6 -# You can add fixtures and/or initialization code here to make experimenting  
7 -# with your gem easier. You can also use a different console, if you like.  
8 -  
9 -# (If you use this, don't forget to add pry to your Gemfile!)  
10 -# require "pry"  
11 -# Pry.start  
12 -  
13 -require "irb"  
14 -IRB.start(__FILE__) 7 +Pry.start
@@ -4,5 +4,3 @@ IFS=$'\n\t' @@ -4,5 +4,3 @@ IFS=$'\n\t'
4 set -vx 4 set -vx
5 5
6 bundle install 6 bundle install
7 -  
8 -# Do any other automated setup that you need to do here  
@@ -5,6 +5,7 @@ require "logger" @@ -5,6 +5,7 @@ require "logger"
5 require "openssl" 5 require "openssl"
6 6
7 require "syspro/api_resource" 7 require "syspro/api_resource"
  8 +require "syspro/errors"
8 require "syspro/get_logon_profile" 9 require "syspro/get_logon_profile"
9 require "syspro/get_version" 10 require "syspro/get_version"
10 require "syspro/logoff" 11 require "syspro/logoff"
lib/syspro/api_resource.rb
@@ -16,13 +16,6 @@ module Syspro @@ -16,13 +16,6 @@ module Syspro
16 "/#{CGI.escape(class_name.downcase)}" 16 "/#{CGI.escape(class_name.downcase)}"
17 end 17 end
18 18
19 - def resource_url  
20 - #unless (id = self["id"])  
21 - #raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", "id")  
22 - #end  
23 - #"#{self.class.resource_url}/#{CGI.escape(id)}"  
24 - end  
25 -  
26 def refresh 19 def refresh
27 resp, opts = request(:get, resource_url, @retrieve_params) 20 resp, opts = request(:get, resource_url, @retrieve_params)
28 initialize_from(resp.data, opts) 21 initialize_from(resp.data, opts)
lib/syspro/errors.rb 0 โ†’ 100644
  1 +module Syspro
  2 + class SysproError < StandardError
  3 + attr_reader :message, :response, :code, :http_body, :http_headers,
  4 + :http_status, :data, :request_id
  5 +
  6 + # Initializes a SysproError.
  7 + def initialize(message = nil, http_status: nil, http_body: nil, data: nil,
  8 + http_headers: nil, code: nil)
  9 + @message = message
  10 + @http_status = http_status
  11 + @http_body = http_body
  12 + @http_headers = http_headers || {}
  13 + @data = data
  14 + @code = code
  15 + @request_id = @http_headers[:request_id]
  16 + end
  17 +
  18 + def to_s
  19 + status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
  20 + id_string = @request_id.nil? ? "" : "(Request #{@request_id}) "
  21 + "#{status_string}#{id_string}#{@message}"
  22 + end
  23 + end
  24 +
  25 + class AuthenticationError < SysproError
  26 + end
  27 +
  28 + class ApiConnectionError < SysproError
  29 + end
  30 +
  31 + class ApiError < SysproError
  32 + end
  33 +
  34 +end
lib/syspro/syspro_client.rb
@@ -40,6 +40,7 @@ module Syspro @@ -40,6 +40,7 @@ module Syspro
40 c.adapter Faraday.default_adapter 40 c.adapter Faraday.default_adapter
41 end 41 end
42 42
  43 + # For now, we're not verifying SSL certificates. The warning will appear.
43 #if Syspro.verify_ssl_certs 44 #if Syspro.verify_ssl_certs
44 #conn.ssl.verify = true 45 #conn.ssl.verify = true
45 #conn.ssl.cert_store = Syspro.ca_store 46 #conn.ssl.cert_store = Syspro.ca_store
@@ -129,7 +130,7 @@ module Syspro @@ -129,7 +130,7 @@ module Syspro
129 end 130 end
130 131
131 def general_api_error(status, body) 132 def general_api_error(status, body)
132 - APIError.new("Invalid response object from API: #{body.inspect} " \ 133 + ApiError.new("Invalid response object from API: #{body.inspect} " \
133 "(HTTP response code was #{status})", 134 "(HTTP response code was #{status})",
134 http_status: status, http_body: body) 135 http_status: status, http_body: body)
135 end 136 end
lib/syspro/syspro_object.rb
@@ -4,6 +4,14 @@ module Syspro @@ -4,6 +4,14 @@ module Syspro
4 4
5 def initialize(id = nil, opts = {}) 5 def initialize(id = nil, opts = {})
6 @opts = Util.normalize_opts(opts) 6 @opts = Util.normalize_opts(opts)
  7 + @original_values = {}
  8 + @values = {}
  9 +
  10 + # This really belongs in APIResource, but not putting it there allows us
  11 + # to have a unified inspect method
  12 + @unsaved_values = Set.new
  13 + @transient_values = Set.new
  14 + @values[:id] = id if id
7 end 15 end
8 16
9 # Determines the equality of two Syspro objects. Syspro objects are 17 # Determines the equality of two Syspro objects. Syspro objects are
@@ -52,7 +60,7 @@ module Syspro @@ -52,7 +60,7 @@ module Syspro
52 private 60 private
53 61
54 # Produces a deep copy of the given object including support for arrays, 62 # Produces a deep copy of the given object including support for arrays,
55 - # hashes, and SysproObject. 63 + # hashes, and SysproObjects.
56 def self.deep_copy(obj) 64 def self.deep_copy(obj)
57 case obj 65 case obj
58 when Array 66 when Array
lib/syspro/syspro_response.rb
1 require "nokogiri" 1 require "nokogiri"
2 2
3 module Syspro 3 module Syspro
4 - # SysproResponse encapsulates some vitals of a response that came back from  
5 - # the Syspro API.  
6 class SysproResponse 4 class SysproResponse
7 - # The data contained by the HTTP body of the response deserialized from  
8 - # JSON.  
9 - attr_accessor :data  
10 -  
11 - # The raw HTTP body of the response.  
12 - attr_accessor :http_body  
13 -  
14 - # A Hash of the HTTP headers of the response.  
15 - attr_accessor :http_headers  
16 -  
17 - # The integer HTTP status code of the response.  
18 - attr_accessor :http_status  
19 -  
20 - # The Syspro request ID of the response.  
21 - attr_accessor :request_id 5 + attr_accessor :data, :http_body, :http_headers, :http_status, :request_id
22 6
23 # Initializes a SysproResponse object from a Hash like the kind returned as 7 # Initializes a SysproResponse object from a Hash like the kind returned as
24 # part of a Faraday exception. 8 # part of a Faraday exception.
25 - #  
26 - # This may throw JSON::ParserError if the response body is not valid JSON.  
27 def self.from_faraday_hash(http_resp) 9 def self.from_faraday_hash(http_resp)
28 resp = SysproResponse.new 10 resp = SysproResponse.new
29 resp.http_body = http_resp[:body] 11 resp.http_body = http_resp[:body]
@@ -35,8 +17,6 @@ module Syspro @@ -35,8 +17,6 @@ module Syspro
35 end 17 end
36 18
37 # Initializes a SysproResponse object from a Faraday HTTP response object. 19 # Initializes a SysproResponse object from a Faraday HTTP response object.
38 - #  
39 - # This may throw JSON::ParserError if the response body is not valid JSON.  
40 def self.from_faraday_response(http_resp) 20 def self.from_faraday_response(http_resp)
41 resp = SysproResponse.new 21 resp = SysproResponse.new
42 resp.http_body = http_resp.body 22 resp.http_body = http_resp.body
lib/syspro/util.rb
@@ -2,9 +2,21 @@ module Syspro @@ -2,9 +2,21 @@ module Syspro
2 class Util 2 class Util
3 # Options that a user is allowed to specify. 3 # Options that a user is allowed to specify.
4 OPTS_USER_SPECIFIED = Set[ 4 OPTS_USER_SPECIFIED = Set[
5 - # :syspro_version 5 + :user_id
6 ].freeze 6 ].freeze
7 7
  8 + # Options that should be copyable from one StripeObject to another
  9 + # including options that may be internal.
  10 + OPTS_COPYABLE = (
  11 + OPTS_USER_SPECIFIED + Set[:api_base]
  12 + ).freeze
  13 +
  14 + # Options that should be persisted between API requests. This includes
  15 + # client, which is an object containing an HTTP client to reuse.
  16 + OPTS_PERSISTABLE = (
  17 + OPTS_USER_SPECIFIED + Set[:client]
  18 + ).freeze
  19 +
8 20
9 def self.objects_to_ids(h) 21 def self.objects_to_ids(h)
10 case h 22 case h
@@ -45,8 +57,7 @@ module Syspro @@ -45,8 +57,7 @@ module Syspro
45 end 57 end
46 end 58 end
47 59
48 -  
49 - # The secondary opts argument can either be a string or hash 60 + # The secondary opts argument can either be a string or hash
50 # Turn this value into an api_key and a set of headers 61 # Turn this value into an api_key and a set of headers
51 def self.normalize_opts(opts) 62 def self.normalize_opts(opts)
52 case opts 63 case opts
syspro.gemspec renamed to syspro-ruby.gemspec
@@ -3,10 +3,10 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) @@ -3,10 +3,10 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3 require "syspro/version" 3 require "syspro/version"
4 4
5 Gem::Specification.new do |spec| 5 Gem::Specification.new do |spec|
6 - spec.name = "syspro" 6 + spec.name = "syspro-ruby"
7 spec.version = Syspro::VERSION 7 spec.version = Syspro::VERSION
8 spec.authors = ["Isaac Lewis"] 8 spec.authors = ["Isaac Lewis"]
9 - spec.email = ["ike@wild.land"] 9 + spec.email = ["isaac@ike.io"]
10 10
11 spec.summary = %q{SYSPRO 7 Api Ruby adapter} 11 spec.summary = %q{SYSPRO 7 Api Ruby adapter}
12 spec.license = "MIT" 12 spec.license = "MIT"
test/client_test.rb
@@ -5,4 +5,15 @@ class SysproClientTest &lt; Minitest::Test @@ -5,4 +5,15 @@ class SysproClientTest &lt; Minitest::Test
5 client = ::Syspro::SysproClient.new 5 client = ::Syspro::SysproClient.new
6 assert_match (/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/), client.get_syspro_version.version 6 assert_match (/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/), client.get_syspro_version.version
7 end 7 end
  8 +
  9 + def test_client_block_execution
  10 + client = ::Syspro::SysproClient.new
  11 +
  12 + version, resp = client.request {
  13 + Syspro::GetVersion.get_version
  14 + }
  15 +
  16 + assert_match version.version, resp.http_body
  17 + assert_match (/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/), version.version
  18 + end
8 end 19 end