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 2  
3 3 git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4 4  
5   -# Specify your gem's dependencies in syspro.gemspec
6 5 gemspec
... ...
README.md
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 5 ## Installation
8 6  
... ... @@ -22,7 +20,57 @@ Or install it yourself as:
22 20  
23 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 75 ## Development
28 76  
... ... @@ -32,7 +80,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32 80  
33 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 85 ## License
38 86  
... ... @@ -40,4 +88,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40 88  
41 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).
... ...
bin/console
... ... @@ -2,13 +2,6 @@
2 2  
3 3 require "bundler/setup"
4 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
... ...
bin/setup
... ... @@ -4,5 +4,3 @@ IFS=$'\n\t'
4 4 set -vx
5 5  
6 6 bundle install
7   -
8   -# Do any other automated setup that you need to do here
... ...
lib/syspro.rb
... ... @@ -5,6 +5,7 @@ require "logger"
5 5 require "openssl"
6 6  
7 7 require "syspro/api_resource"
  8 +require "syspro/errors"
8 9 require "syspro/get_logon_profile"
9 10 require "syspro/get_version"
10 11 require "syspro/logoff"
... ...
lib/syspro/api_resource.rb
... ... @@ -16,13 +16,6 @@ module Syspro
16 16 "/#{CGI.escape(class_name.downcase)}"
17 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 19 def refresh
27 20 resp, opts = request(:get, resource_url, @retrieve_params)
28 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 40 c.adapter Faraday.default_adapter
41 41 end
42 42  
  43 + # For now, we're not verifying SSL certificates. The warning will appear.
43 44 #if Syspro.verify_ssl_certs
44 45 #conn.ssl.verify = true
45 46 #conn.ssl.cert_store = Syspro.ca_store
... ... @@ -129,7 +130,7 @@ module Syspro
129 130 end
130 131  
131 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 134 "(HTTP response code was #{status})",
134 135 http_status: status, http_body: body)
135 136 end
... ...
lib/syspro/syspro_object.rb
... ... @@ -4,6 +4,14 @@ module Syspro
4 4  
5 5 def initialize(id = nil, opts = {})
6 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 15 end
8 16  
9 17 # Determines the equality of two Syspro objects. Syspro objects are
... ... @@ -52,7 +60,7 @@ module Syspro
52 60 private
53 61  
54 62 # Produces a deep copy of the given object including support for arrays,
55   - # hashes, and SysproObject.
  63 + # hashes, and SysproObjects.
56 64 def self.deep_copy(obj)
57 65 case obj
58 66 when Array
... ...
lib/syspro/syspro_response.rb
1 1 require "nokogiri"
2 2  
3 3 module Syspro
4   - # SysproResponse encapsulates some vitals of a response that came back from
5   - # the Syspro API.
6 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 7 # Initializes a SysproResponse object from a Hash like the kind returned as
24 8 # part of a Faraday exception.
25   - #
26   - # This may throw JSON::ParserError if the response body is not valid JSON.
27 9 def self.from_faraday_hash(http_resp)
28 10 resp = SysproResponse.new
29 11 resp.http_body = http_resp[:body]
... ... @@ -35,8 +17,6 @@ module Syspro
35 17 end
36 18  
37 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 20 def self.from_faraday_response(http_resp)
41 21 resp = SysproResponse.new
42 22 resp.http_body = http_resp.body
... ...
lib/syspro/util.rb
... ... @@ -2,9 +2,21 @@ module Syspro
2 2 class Util
3 3 # Options that a user is allowed to specify.
4 4 OPTS_USER_SPECIFIED = Set[
5   - # :syspro_version
  5 + :user_id
6 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 21 def self.objects_to_ids(h)
10 22 case h
... ... @@ -45,8 +57,7 @@ module Syspro
45 57 end
46 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 61 # Turn this value into an api_key and a set of headers
51 62 def self.normalize_opts(opts)
52 63 case opts
... ...
syspro.gemspec renamed to syspro-ruby.gemspec
... ... @@ -3,10 +3,10 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3 3 require "syspro/version"
4 4  
5 5 Gem::Specification.new do |spec|
6   - spec.name = "syspro"
  6 + spec.name = "syspro-ruby"
7 7 spec.version = Syspro::VERSION
8 8 spec.authors = ["Isaac Lewis"]
9   - spec.email = ["ike@wild.land"]
  9 + spec.email = ["isaac@ike.io"]
10 10  
11 11 spec.summary = %q{SYSPRO 7 Api Ruby adapter}
12 12 spec.license = "MIT"
... ...
test/client_test.rb
... ... @@ -5,4 +5,15 @@ class SysproClientTest &lt; Minitest::Test
5 5 client = ::Syspro::SysproClient.new
6 6 assert_match (/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/), client.get_syspro_version.version
7 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 19 end
... ...