Commit 0c0af54a8bd446733ec29ed87509d6c12b68d578
1 parent
eef01045
error handling; cleanup; rename to `syspro-ruby`
Showing
13 changed files
with
131 additions
and
54 deletions
Show diff stats
Gemfile
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
lib/syspro.rb
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) | ... | ... |
| 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 < 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 | ... | ... |