visma_eaccounting 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a737f9498f23b71408ea0cb7354a4ab43f1a0d8857b45197264d2917a0a4bda8
4
+ data.tar.gz: 53477ec8fd7db0e6e6d21bbcb8c99e2d210fcf280be63998edbf6f6426a31276
5
+ SHA512:
6
+ metadata.gz: 96c9e12c4139c153d476b980b8fe284b54529badab45f84887688e6a02d79f5db1433924f2217fba461a8981d243a514e7e7c51f6c2d5f82b234a5ef95e58ce4
7
+ data.tar.gz: 753cd063742597f284bafcec09031e9ad1bda77816c6155599fcb8be4803f93352127390ff7019512e5ea6bb4ba03e14b2740e07de5846b8b9b2ffc8372c3df1
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,49 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ # jeweler generated
15
+ pkg
16
+
17
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
18
+ #
19
+ # * Create a file at ~/.gitignore
20
+ # * Include files you want ignored
21
+ # * Run: git config --global core.excludesfile ~/.gitignore
22
+ #
23
+ # After doing this, these files will be ignored in all your git projects,
24
+ # saving you from having to 'pollute' every project you touch with them
25
+ #
26
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
27
+ #
28
+ # For MacOS:
29
+ #
30
+ .DS_Store
31
+ #
32
+ # For TextMate
33
+ #*.tmproj
34
+ #tmtags
35
+ #
36
+ # For emacs:
37
+ #*~
38
+ #\#*
39
+ #.\#*
40
+ #
41
+ # For vim:
42
+ #*.swp
43
+
44
+ bin
45
+ cache
46
+ gems
47
+ specifications
48
+ Gemfile.lock
49
+ .rvmrc
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ before_install:
5
+ - gem install bundler # -v 1.7.14 if a specific version is needed
6
+ rvm:
7
+ - 2.0.0
8
+ - 2.1.5
9
+ - 2.2.2
10
+ - 2.3.3
data/CHANGELOG.md ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ platforms :rbx do
4
+ gem 'rubysl', '~> 2.2.0'
5
+ gem 'rubinius-developer_tools'
6
+ end
7
+
8
+ group :development, :test do
9
+ gem 'webmock', '~>1.24.0'
10
+ end
11
+
12
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010-2017 Espen Antonsen and Amro Mousa
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,194 @@
1
+ # visma_eaccounting
2
+
3
+ VismaEaccounting is an API wrapper for the Visma eAccounting [API](https://developer.vismaonline.com/).
4
+
5
+ ## Important Notes
6
+
7
+ VismaEaccounting returns a `VismaEaccounting::Response` instead of the response body directly. `VismaEaccounting::Response` exposes the parsed response `body` and `headers`.
8
+
9
+ ## Installation
10
+
11
+ $ gem install visma_eaccounting
12
+
13
+ ## Requirements
14
+
15
+ A Visma eAccounting account and oAuth client id.
16
+
17
+ ## Usage
18
+
19
+ First, create a *one-time use instance* of `VismaEaccounting::Request`:
20
+
21
+ ```ruby
22
+ visma_eaccounting = VismaEaccounting::Request.new(token: "your_token")
23
+ ```
24
+
25
+ ***Note*** Only reuse instances of VismaEaccounting after terminating a call with a verb, which makes a request. Requests are light weight objects that update an internal path based on your call chain. When you terminate a call chain with a verb, a request instance makes a request and resets the path.
26
+
27
+ You can set an individual request's `timeout` and `open_timeout` like this:
28
+
29
+ ```ruby
30
+ visma_eaccounting.timeout = 30
31
+ visma_eaccounting.open_timeout = 30
32
+ ```
33
+
34
+ You can read about `timeout` and `open_timeout` in the [Net::HTTP](https://ruby-doc.org/stdlib-2.3.3/libdoc/net/http/rdoc/Net/HTTP.html) doc.
35
+
36
+ Now you can make requests using the resources defined in [the Visma eAccounting's docs](https://developer.vismaonline.com/#APIReference). Resource IDs
37
+ are specified inline and a `CRUD` (`create`, `retrieve`, `update`, `upsert`, or `delete`) verb initiates the request. `upsert` lets you update a record, if it exists, or insert it otherwise where supported by Visma's API.
38
+
39
+ You can specify `headers`, `params`, and `body` when calling a `CRUD` method. For example:
40
+
41
+ ```ruby
42
+ visma_eaccounting.customers.retrieve(headers: {"SomeHeader": "SomeHeaderValue"}, params: {"query_param": "query_param_value"})
43
+ ```
44
+
45
+ Of course, `body` is only supported on `create` and `update` calls. Those map to HTTP `POST` and `PUT` verbs respectively.
46
+
47
+ You can set `token`, `timeout`, `open_timeout`, `faraday_adapter`, `proxy`, `symbolize_keys`, `logger`, and `debug` globally:
48
+
49
+ ```ruby
50
+ VismaEaccounting::Request.token = "your_token"
51
+ VismaEaccounting::Request.timeout = 15
52
+ VismaEaccounting::Request.open_timeout = 15
53
+ VismaEaccounting::Request.symbolize_keys = true
54
+ VismaEaccounting::Request.debug = false
55
+ ```
56
+
57
+ For example, you could set the values above in an `initializer` file in your `Rails` app (e.g. your\_app/config/initializers/visma_eaccounting.rb).
58
+
59
+ Assuming you've set an `token` on VismaEaccounting, you can conveniently make API calls on the class itself:
60
+
61
+ ```ruby
62
+ VismaEaccounting::Request.customers.retrieve
63
+ ```
64
+
65
+ ***Note*** Substitute an underscore if a resource name contains a hyphen.
66
+
67
+ Pass `symbolize_keys: true` to use symbols (instead of strings) as hash keys in API responses.
68
+
69
+ ```ruby
70
+ visma_eaccounting = VismaEaccounting::Request.new(token: "your_token", symbolize_keys: true)
71
+ ```
72
+
73
+ Visma's [API documentation](https://developer.vismaonline.com/#APIReference) is a list of available endpoints.
74
+
75
+ ## Environments
76
+
77
+ The default environment is ```:production```. To use the sandbox environment you can set ```:sandbox``` in constructor or globally. This will set the default ```api_endpoint``` URL.
78
+
79
+ ## Debug Logging
80
+
81
+ Pass `debug: true` to enable debug logging to STDOUT.
82
+
83
+ ```ruby
84
+ visma_eaccounting = VismaEaccounting::Request.new(token: "your_token", debug: true)
85
+ ```
86
+
87
+ ### Custom logger
88
+
89
+ Ruby `Logger.new` is used by default, but it can be overrided using:
90
+
91
+ ```ruby
92
+ visma_eaccounting = VismaEaccounting::Request.new(token: "your_token", debug: true, logger: MyLogger.new)
93
+ ```
94
+
95
+ Logger can be also set by globally:
96
+
97
+ ```ruby
98
+ VismaEaccounting::Request.logger = MyLogger.new
99
+ ```
100
+
101
+ ## Examples
102
+
103
+ ### Customers
104
+
105
+ Fetch all customers:
106
+
107
+ ```ruby
108
+ visma_eaccounting.customers.retrieve
109
+ ```
110
+
111
+ By default the Visma API returns 50 results. To set the count to 50:
112
+
113
+ ```ruby
114
+ visma_eaccounting.customers.retrieve(params: {"pagesize": "100"})
115
+ ```
116
+
117
+ And to retrieve the next 50 members:
118
+
119
+ ```ruby
120
+ visma_eaccounting.customers.retrieve(params: {"pagesize": "100", "page": "2"})
121
+ ```
122
+
123
+ Query using filters:
124
+
125
+ ```ruby
126
+ visma_eaccounting.customers.retrieve(params: {"filter": "contains(Name, ‘MakePlans’)"})
127
+ ```
128
+
129
+ Retrieving a specific customer looks like:
130
+
131
+ ```ruby
132
+ visma_eaccounting.customers(customer_id).retrieve
133
+ ```
134
+
135
+ Add a new customer:
136
+
137
+ ```ruby
138
+ visma_eaccounting.customers.create(body: {"Name": "MakePlans AS"})
139
+ ```
140
+
141
+ ### Fields
142
+
143
+ Only retrieve ids and names for fetched customers:
144
+
145
+ ```ruby
146
+ visma_eaccounting.customers.retrieve(params: {"select": "Id, Name"})
147
+ ```
148
+
149
+ ### Error handling
150
+
151
+ VismaEaccounting raises an error when the API returns an error.
152
+
153
+ `VismaEaccounting::VismaEaccountingError` has the following attributes: `title`, `detail`, `body`, `raw_body`, `status_code`. Some or all of these may not be
154
+ available depending on the nature of the error. For example:
155
+
156
+ ```ruby
157
+ begin
158
+ visma_eaccounting.customers(customer_id).members.create(body: body)
159
+ rescue VismaEaccounting::VismaEaccountingError => e
160
+ puts "Houston, we have a problem: #{e.message} - #{e.raw_body}"
161
+ end
162
+ ```
163
+
164
+ ### Other
165
+
166
+ You can set an optional proxy url like this (or with an environment variable VISMA_PROXY):
167
+
168
+ ```ruby
169
+ visma_eaccounting.proxy = 'http://your_proxy.com:80'
170
+ ```
171
+
172
+ You can set a different [Faraday adapter](https://github.com/lostisland/faraday) during initialization:
173
+
174
+ ```ruby
175
+ visma_eaccounting = VismaEaccounting::Request.new(token: "your_token", faraday_adapter: :net_http)
176
+ ```
177
+
178
+ #### Initialization
179
+
180
+ ```ruby
181
+ visma_eaccounting = VismaEaccounting::Request.new(token: "your_token")
182
+ ```
183
+
184
+ ## Thanks
185
+
186
+ Thanks to everyone who has [contributed](https://github.com/espen/visma_eaccounting/contributors) to VismaEaccounting's development.
187
+
188
+ ## Credits
189
+
190
+ Based on [Gibbon](https://github.com/amro/gibbon) by [Amro Mousa](https://github.com/amro).
191
+
192
+ ## Copyright
193
+
194
+ * Copyright (c) 2010-2017 Espen Antonsen and Amro Mousa. See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubygems/specification'
4
+ require 'bundler/gem_tasks'
5
+
6
+ task :default => :spec
7
+ desc "Run specs"
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.pattern = FileList['spec/**/*_spec.rb']
10
+ t.rspec_opts = %w(-fd --color)
11
+ end
@@ -0,0 +1,29 @@
1
+ module VismaEaccounting
2
+ class APIError < StandardError
3
+ attr_reader :title, :detail, :body, :raw_body, :status_code
4
+
5
+ def initialize(message = "", params = {})
6
+ @title = params[:title]
7
+ @detail = params[:detail]
8
+ @body = params[:body]
9
+ @raw_body = params[:raw_body]
10
+ @status_code = params[:status_code]
11
+
12
+ super(message)
13
+ end
14
+
15
+ def to_s
16
+ super + " " + instance_variables_to_s
17
+ end
18
+
19
+ private
20
+
21
+ def instance_variables_to_s
22
+ [:title, :detail, :body, :raw_body, :status_code].map do |attr|
23
+ attr_value = send(attr)
24
+
25
+ "@#{attr}=#{attr_value.inspect}"
26
+ end.join(", ")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,193 @@
1
+ module VismaEaccounting
2
+ class APIRequest
3
+
4
+ def initialize(builder: nil)
5
+ @request_builder = builder
6
+ end
7
+
8
+ def post(params: nil, headers: nil, body: nil)
9
+ validate_token
10
+
11
+ begin
12
+ response = self.rest_client.post do |request|
13
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
14
+ end
15
+ parse_response(response)
16
+ rescue => e
17
+ handle_error(e)
18
+ end
19
+ end
20
+
21
+ def patch(params: nil, headers: nil, body: nil)
22
+ validate_token
23
+
24
+ begin
25
+ response = self.rest_client.patch do |request|
26
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
27
+ end
28
+ parse_response(response)
29
+ rescue => e
30
+ handle_error(e)
31
+ end
32
+ end
33
+
34
+ def put(params: nil, headers: nil, body: nil)
35
+ validate_token
36
+
37
+ begin
38
+ response = self.rest_client.put do |request|
39
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
40
+ end
41
+ parse_response(response)
42
+ rescue => e
43
+ handle_error(e)
44
+ end
45
+ end
46
+
47
+ def get(params: nil, headers: nil)
48
+ validate_token
49
+
50
+ begin
51
+ response = self.rest_client.get do |request|
52
+ configure_request(request: request, params: params, headers: headers)
53
+ end
54
+ parse_response(response)
55
+ rescue => e
56
+ handle_error(e)
57
+ end
58
+ end
59
+
60
+ def delete(params: nil, headers: nil)
61
+ validate_token
62
+
63
+ begin
64
+ response = self.rest_client.delete do |request|
65
+ configure_request(request: request, params: params, headers: headers)
66
+ end
67
+ parse_response(response)
68
+ rescue => e
69
+ handle_error(e)
70
+ end
71
+ end
72
+
73
+ protected
74
+
75
+ # Convenience accessors
76
+
77
+ def token
78
+ @request_builder.token
79
+ end
80
+
81
+ def timeout
82
+ @request_builder.timeout
83
+ end
84
+
85
+ def open_timeout
86
+ @request_builder.open_timeout
87
+ end
88
+
89
+ def proxy
90
+ @request_builder.proxy
91
+ end
92
+
93
+ def adapter
94
+ @request_builder.faraday_adapter
95
+ end
96
+
97
+ def symbolize_keys
98
+ @request_builder.symbolize_keys
99
+ end
100
+
101
+ # Helpers
102
+
103
+ def handle_error(error)
104
+ error_params = {}
105
+
106
+ begin
107
+ if error.is_a?(Faraday::Error::ClientError) && error.response
108
+ error_params[:status_code] = error.response[:status]
109
+ error_params[:raw_body] = error.response[:body]
110
+
111
+ parsed_response = MultiJson.load(error.response[:body], symbolize_keys: symbolize_keys)
112
+
113
+ if parsed_response
114
+ error_params[:body] = parsed_response
115
+
116
+ title_key = symbolize_keys ? :title : "title"
117
+ detail_key = symbolize_keys ? :detail : "detail"
118
+
119
+ error_params[:title] = parsed_response[title_key] if parsed_response[title_key]
120
+ error_params[:detail] = parsed_response[detail_key] if parsed_response[detail_key]
121
+ end
122
+
123
+ end
124
+ rescue MultiJson::ParseError
125
+ end
126
+
127
+ error_to_raise = APIError.new(error.message, error_params)
128
+
129
+ raise error_to_raise
130
+ end
131
+
132
+ def configure_request(request: nil, params: nil, headers: nil, body: nil)
133
+ if request
134
+ request.params.merge!(params) if params
135
+ request.headers['Content-Type'] = 'application/json'
136
+ request.headers.merge!(headers) if headers
137
+ request.body = body if body
138
+ request.options.timeout = self.timeout
139
+ request.options.open_timeout = self.open_timeout
140
+ end
141
+ end
142
+
143
+ def rest_client
144
+ client = Faraday.new(self.api_url, proxy: self.proxy, ssl: { version: "TLSv1_2" }) do |faraday|
145
+ faraday.response :raise_error
146
+ faraday.adapter adapter
147
+ if @request_builder.debug
148
+ faraday.response :logger, @request_builder.logger, bodies: true
149
+ end
150
+ end
151
+ client.authorization :Bearer, self.token
152
+ client
153
+ end
154
+
155
+ def parse_response(response)
156
+ parsed_response = nil
157
+
158
+ if response.body && !response.body.empty?
159
+ begin
160
+ headers = response.headers
161
+ body = MultiJson.load(response.body, symbolize_keys: symbolize_keys)
162
+ parsed_response = Response.new(headers: headers, body: body)
163
+ rescue MultiJson::ParseError
164
+ error_params = { title: "UNPARSEABLE_RESPONSE", status_code: 500 }
165
+ error = APIError.new("Unparseable response: #{response.body}", error_params)
166
+ raise error
167
+ end
168
+ end
169
+
170
+ parsed_response
171
+ end
172
+
173
+ def validate_token
174
+ token = self.token
175
+ unless token
176
+ raise VismaEaccounting::VismaEaccountingError, "You must set an token prior to making a call"
177
+ end
178
+ end
179
+
180
+ def api_url
181
+ base_api_url + @request_builder.path
182
+ end
183
+
184
+ def base_api_url
185
+ case self.class.api_environment
186
+ when :sandbox
187
+ "https://eaccountingapi-sandbox.test.vismaonline.com/v2/"
188
+ when :production
189
+ "https://eaccountingapi.vismaonline.com/v2/"
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,90 @@
1
+ module VismaEaccounting
2
+ class Request
3
+ attr_accessor :token, :api_environment, :api_endpoint, :timeout, :open_timeout, :proxy, :faraday_adapter, :symbolize_keys, :debug, :logger
4
+
5
+ DEFAULT_TIMEOUT = 60
6
+ DEFAULT_OPEN_TIMEOUT = 60
7
+ DEFAULT_API_ENVIRONMENT = :production
8
+
9
+ def initialize(token: nil, api_environment: nil, api_endpoint: nil, timeout: nil, open_timeout: nil, proxy: nil, faraday_adapter: nil, symbolize_keys: false, debug: false, logger: nil)
10
+ @path_parts = []
11
+ @token = token || self.class.token
12
+ @token = @token.strip if @token
13
+ @api_environment = api_environment || self.class.api_environment || DEFAULT_API_ENVIRONMENT
14
+ @api_endpoint = api_endpoint || self.class.api_endpoint
15
+ @timeout = timeout || self.class.timeout || DEFAULT_TIMEOUT
16
+ @open_timeout = open_timeout || self.class.open_timeout || DEFAULT_OPEN_TIMEOUT
17
+ @proxy = proxy || self.class.proxy || ENV['VISMA_PROXY_URL']
18
+ @faraday_adapter = faraday_adapter || Faraday.default_adapter
19
+ @symbolize_keys = symbolize_keys || self.class.symbolize_keys || false
20
+ @debug = debug || self.class.debug || false
21
+ @logger = logger || self.class.logger || ::Logger.new(STDOUT)
22
+ end
23
+
24
+ def method_missing(method, *args)
25
+ # To support underscores, we replace them with hyphens when calling the API
26
+ @path_parts << method.to_s.gsub("_", "-").downcase
27
+ @path_parts << args if args.length > 0
28
+ @path_parts.flatten!
29
+ self
30
+ end
31
+
32
+ def respond_to_missing?(method_name, include_private = false)
33
+ true
34
+ end
35
+
36
+ def send(*args)
37
+ if args.length == 0
38
+ method_missing(:send, args)
39
+ else
40
+ __send__(*args)
41
+ end
42
+ end
43
+
44
+ def path
45
+ @path_parts.join('/')
46
+ end
47
+
48
+ def create(params: nil, headers: nil, body: nil)
49
+ APIRequest.new(builder: self).post(params: params, headers: headers, body: body)
50
+ ensure
51
+ reset
52
+ end
53
+
54
+ def update(params: nil, headers: nil, body: nil)
55
+ APIRequest.new(builder: self).put(params: params, headers: headers, body: body)
56
+ ensure
57
+ reset
58
+ end
59
+
60
+ def retrieve(params: nil, headers: nil)
61
+ APIRequest.new(builder: self).get(params: params, headers: headers)
62
+ ensure
63
+ reset
64
+ end
65
+
66
+ def delete(params: nil, headers: nil)
67
+ APIRequest.new(builder: self).delete(params: params, headers: headers)
68
+ ensure
69
+ reset
70
+ end
71
+
72
+ protected
73
+
74
+ def reset
75
+ @path_parts = []
76
+ end
77
+
78
+ class << self
79
+ attr_accessor :token, :timeout, :open_timeout, :api_environment, :api_endpoint, :proxy, :faraday_adapter, :symbolize_keys, :debug, :logger
80
+
81
+ def method_missing(sym, *args, &block)
82
+ new(token: self.token, api_environment: self.api_environment, api_endpoint: self.api_endpoint, timeout: self.timeout, open_timeout: self.open_timeout, faraday_adapter: self.faraday_adapter, symbolize_keys: self.symbolize_keys, debug: self.debug, proxy: self.proxy, logger: self.logger).send(sym, *args, &block)
83
+ end
84
+
85
+ def respond_to_missing?(method_name, include_private = false)
86
+ true
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,10 @@
1
+ module VismaEaccounting
2
+ class Response
3
+ attr_accessor :body, :headers
4
+
5
+ def initialize(body: {}, headers: {})
6
+ @body = body
7
+ @headers = headers
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module VismaEaccounting
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,3 @@
1
+ module VismaEaccounting
2
+ class VismaEaccountingError < StandardError; end
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'faraday'
2
+ require 'multi_json'
3
+ require 'cgi'
4
+ require 'logger'
5
+
6
+ require 'visma_eaccounting/visma_eaccounting_error'
7
+ require 'visma_eaccounting/api_error'
8
+ require 'visma_eaccounting/request'
9
+ require 'visma_eaccounting/api_request'
10
+ require 'visma_eaccounting/response'
11
+
12
+ module VismaEaccounting
13
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.setup(:default, :development)
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'visma_eaccounting'
9
+
10
+ RSpec.configure do |config|
11
+ config.color = true
12
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe VismaEaccounting::APIError do
4
+ let(:message) { 'Foo' }
5
+ let(:params) do
6
+ {
7
+ title: 'error_title',
8
+ detail: 'error_detail',
9
+ body: 'error_body',
10
+ raw_body: 'error_raw_body',
11
+ status_code: 'error_status_code'
12
+ }
13
+ end
14
+
15
+ before do
16
+ @visma_eaccounting = VismaEaccounting::APIError.new(message, params)
17
+ end
18
+
19
+ it "adds the error params to the error message" do
20
+ expected_message = "Foo " \
21
+ "@title=\"error_title\", " \
22
+ "@detail=\"error_detail\", " \
23
+ "@body=\"error_body\", " \
24
+ "@raw_body=\"error_raw_body\", " \
25
+ "@status_code=\"error_status_code\""
26
+
27
+ expect(@visma_eaccounting.message).to eq(expected_message)
28
+ end
29
+
30
+ it 'sets the title attribute' do
31
+ expect(@visma_eaccounting.title).to eq(params[:title])
32
+ end
33
+
34
+ it 'sets the detail attribute' do
35
+ expect(@visma_eaccounting.detail).to eq(params[:detail])
36
+ end
37
+
38
+ it 'sets the body attribute' do
39
+ expect(@visma_eaccounting.body).to eq(params[:body])
40
+ end
41
+
42
+ it 'sets the raw_body attribute' do
43
+ expect(@visma_eaccounting.raw_body).to eq(params[:raw_body])
44
+ end
45
+
46
+ it 'sets the status_code attribute' do
47
+ expect(@visma_eaccounting.status_code).to eq(params[:status_code])
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'webmock/rspec'
3
+
4
+ describe VismaEaccounting::APIRequest do
5
+ let(:token) { "ionfean8hfaeo8AUfenao(ea" }
6
+
7
+ before do
8
+ @visma_eaccounting = VismaEaccounting::Request.new(token: token)
9
+ @api_root = "https://eaccountingapi-sandbox.test.vismaonline.com/v2"
10
+ end
11
+
12
+ it "surfaces client request exceptions as a VismaEaccounting::APIError" do
13
+ exception = Faraday::Error::ClientError.new("the server responded with status 503")
14
+ stub_request(:get, "#{@api_root}/customers").to_raise(exception)
15
+ expect { @visma_eaccounting.customers.retrieve }.to raise_error(VismaEaccounting::APIError)
16
+ end
17
+
18
+ it "surfaces an unparseable client request exception as a VismaEaccounting::APIError" do
19
+ exception = Faraday::Error::ClientError.new(
20
+ "the server responded with status 503")
21
+ stub_request(:get, "#{@api_root}/customers").to_raise(exception)
22
+ expect { @visma_eaccounting.customers.retrieve }.to raise_error(VismaEaccounting::APIError)
23
+ end
24
+
25
+ it "surfaces an unparseable response body as a VismaEaccounting::APIError" do
26
+ response_values = {:status => 503, :headers => {}, :body => '[foo]'}
27
+ exception = Faraday::Error::ClientError.new("the server responded with status 503", response_values)
28
+
29
+ stub_request(:get, "#{@api_root}/customers").to_raise(exception)
30
+ expect { @visma_eaccounting.customers.retrieve }.to raise_error(VismaEaccounting::APIError)
31
+ end
32
+
33
+ context "handle_error" do
34
+ it "includes status and raw body even when json can't be parsed" do
35
+ response_values = {:status => 503, :headers => {}, :body => 'A non JSON response'}
36
+ exception = Faraday::Error::ClientError.new("the server responded with status 503", response_values)
37
+ api_request = VismaEaccounting::APIRequest.new(builder: VismaEaccounting::Request)
38
+ begin
39
+ api_request.send :handle_error, exception
40
+ rescue => boom
41
+ expect(boom.status_code).to eq 503
42
+ expect(boom.raw_body).to eq "A non JSON response"
43
+ end
44
+ end
45
+
46
+ context "when symbolize_keys is true" do
47
+ it "sets title and detail on the error params" do
48
+ response_values = {:status => 422, :headers => {}, :body => '{"title": "foo", "detail": "bar"}'}
49
+ exception = Faraday::Error::ClientError.new("the server responded with status 422", response_values)
50
+ api_request = VismaEaccounting::APIRequest.new(builder: VismaEaccounting::Request.new(symbolize_keys: true))
51
+ begin
52
+ api_request.send :handle_error, exception
53
+ rescue => boom
54
+ expect(boom.title).to eq "foo"
55
+ expect(boom.detail).to eq "bar"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+ require 'cgi'
3
+
4
+ describe VismaEaccounting do
5
+ describe "attributes" do
6
+ before do
7
+ VismaEaccounting::APIRequest.send(:public, *VismaEaccounting::APIRequest.protected_instance_methods)
8
+
9
+ @token = "ifeaean8hfaeo8AUfenao(ea"
10
+ @proxy = 'the_proxy'
11
+ end
12
+
13
+ it "have no API by default" do
14
+ @visma_eaccounting = VismaEaccounting::Request.new
15
+ expect(@visma_eaccounting.token).to be_nil
16
+ end
17
+ it "sets an API key in the constructor" do
18
+ @visma_eaccounting = VismaEaccounting::Request.new(token: @token)
19
+ expect(@visma_eaccounting.token).to eq(@token)
20
+ end
21
+
22
+ it "sets an API key via setter" do
23
+ @visma_eaccounting = VismaEaccounting::Request.new
24
+ @visma_eaccounting.token = @token
25
+ expect(@visma_eaccounting.token).to eq(@token)
26
+ end
27
+
28
+ it "sets timeout and get" do
29
+ @visma_eaccounting = VismaEaccounting::Request.new
30
+ timeout = 30
31
+ @visma_eaccounting.timeout = timeout
32
+ expect(timeout).to eq(@visma_eaccounting.timeout)
33
+ end
34
+
35
+ it "sets the open_timeout and get" do
36
+ @visma_eaccounting = VismaEaccounting::Request.new
37
+ open_timeout = 30
38
+ @visma_eaccounting.open_timeout = open_timeout
39
+ expect(open_timeout).to eq(@visma_eaccounting.open_timeout)
40
+ end
41
+
42
+ it "timeout properly passed to APIRequest" do
43
+ @visma_eaccounting = VismaEaccounting::Request.new
44
+ timeout = 30
45
+ @visma_eaccounting.timeout = timeout
46
+ @request = VismaEaccounting::APIRequest.new(builder: @visma_eaccounting)
47
+ expect(timeout).to eq(@request.timeout)
48
+ end
49
+
50
+ it "timeout properly based on open_timeout passed to APIRequest" do
51
+ @visma_eaccounting = VismaEaccounting::Request.new
52
+ open_timeout = 30
53
+ @visma_eaccounting.open_timeout = open_timeout
54
+ @request = VismaEaccounting::APIRequest.new(builder: @visma_eaccounting)
55
+ expect(open_timeout).to eq(@request.open_timeout)
56
+ end
57
+
58
+ it "has no Proxy url by default" do
59
+ @visma_eaccounting = VismaEaccounting::Request.new
60
+ expect(@visma_eaccounting.proxy).to be_nil
61
+ end
62
+
63
+ it "sets an proxy url key from the 'VISMA_PROXY_URL' ENV variable" do
64
+ ENV['VISMA_PROXY_URL'] = @proxy
65
+ @visma_eaccounting = VismaEaccounting::Request.new
66
+ expect(@visma_eaccounting.proxy).to eq(@proxy)
67
+ ENV.delete('VISMA_PROXY_URL')
68
+ end
69
+
70
+ it "sets an API key via setter" do
71
+ @visma_eaccounting = VismaEaccounting::Request.new
72
+ @visma_eaccounting.proxy = @proxy
73
+ expect(@visma_eaccounting.proxy).to eq(@proxy)
74
+ end
75
+
76
+ it "sets an adapter in the constructor" do
77
+ adapter = :em_synchrony
78
+ @visma_eaccounting = VismaEaccounting::Request.new(faraday_adapter: adapter)
79
+ expect(@visma_eaccounting.faraday_adapter).to eq(adapter)
80
+ end
81
+
82
+ it "symbolize_keys false by default" do
83
+ @visma_eaccounting = VismaEaccounting::Request.new
84
+ expect(@visma_eaccounting.symbolize_keys).to be false
85
+ end
86
+
87
+ it "sets symbolize_keys in the constructor" do
88
+ @visma_eaccounting = VismaEaccounting::Request.new(symbolize_keys: true)
89
+ expect(@visma_eaccounting.symbolize_keys).to be true
90
+ end
91
+
92
+ it "sets symbolize_keys in the constructor" do
93
+ @visma_eaccounting = VismaEaccounting::Request.new(symbolize_keys: true)
94
+ expect(@visma_eaccounting.symbolize_keys).to be true
95
+ end
96
+
97
+ it "debug false by default" do
98
+ @visma_eaccounting = VismaEaccounting::Request.new
99
+ expect(@visma_eaccounting.debug).to be false
100
+ end
101
+
102
+ it "sets debug in the constructor" do
103
+ @visma_eaccounting = VismaEaccounting::Request.new(debug: true)
104
+ expect(@visma_eaccounting.debug).to be true
105
+ end
106
+
107
+ it "sets logger in constructor" do
108
+ logger = double(:logger)
109
+ @visma_eaccounting = VismaEaccounting::Request.new(logger: logger)
110
+ expect(@visma_eaccounting.logger).to eq(logger)
111
+ end
112
+
113
+ it "is a Logger instance by default" do
114
+ @visma_eaccounting = VismaEaccounting::Request.new
115
+ expect(@visma_eaccounting.logger).to be_a Logger
116
+ end
117
+
118
+ it "api_environment production by default" do
119
+ @visma_eaccounting = VismaEaccounting::Request.new
120
+ expect(@visma_eaccounting.api_environment).to be :production
121
+ end
122
+
123
+ it "sets api_environment in the constructor" do
124
+ @visma_eaccounting = VismaEaccounting::Request.new(api_environment: :sandbox)
125
+ expect(@visma_eaccounting.api_environment).to be :sandbox
126
+ end
127
+
128
+ end
129
+
130
+ describe "build api url" do
131
+ before do
132
+ VismaEaccounting::APIRequest.send(:public, *VismaEaccounting::APIRequest.protected_instance_methods)
133
+
134
+ @visma_eaccounting = VismaEaccounting::Request.new
135
+ end
136
+
137
+ it "doesn't allow empty api key" do
138
+ expect {@visma_eaccounting.try.retrieve}.to raise_error(VismaEaccounting::VismaEaccountingError)
139
+ end
140
+
141
+ end
142
+
143
+ describe "class variables" do
144
+ let(:logger) { double(:logger) }
145
+
146
+ before do
147
+ VismaEaccounting::Request.token = "ifeaean8hfaeo8AUfenao(ea"
148
+ VismaEaccounting::Request.timeout = 15
149
+ VismaEaccounting::Request.api_environment = :sandbox
150
+ VismaEaccounting::Request.api_endpoint = 'https://eaccountingapi.example.org/v1337/'
151
+ VismaEaccounting::Request.logger = logger
152
+ VismaEaccounting::Request.proxy = "http://1234.com"
153
+ VismaEaccounting::Request.symbolize_keys = true
154
+ VismaEaccounting::Request.faraday_adapter = :net_http
155
+ VismaEaccounting::Request.debug = true
156
+ end
157
+
158
+ after do
159
+ VismaEaccounting::Request.token = nil
160
+ VismaEaccounting::Request.timeout = nil
161
+ VismaEaccounting::Request.api_environment = nil
162
+ VismaEaccounting::Request.api_endpoint = nil
163
+ VismaEaccounting::Request.logger = nil
164
+ VismaEaccounting::Request.proxy = nil
165
+ VismaEaccounting::Request.symbolize_keys = nil
166
+ VismaEaccounting::Request.faraday_adapter = nil
167
+ VismaEaccounting::Request.debug = nil
168
+ end
169
+
170
+ it "set api key on new instances" do
171
+ expect(VismaEaccounting::Request.new.token).to eq(VismaEaccounting::Request.token)
172
+ end
173
+
174
+ it "set timeout on new instances" do
175
+ expect(VismaEaccounting::Request.new.timeout).to eq(VismaEaccounting::Request.timeout)
176
+ end
177
+
178
+ it "set api_environment on new instances" do
179
+ expect(VismaEaccounting::Request.api_environment).not_to be_nil
180
+ expect(VismaEaccounting::Request.new.api_environment).to eq(VismaEaccounting::Request.api_environment)
181
+ end
182
+
183
+ it "set api_endpoint on new instances" do
184
+ expect(VismaEaccounting::Request.api_endpoint).not_to be_nil
185
+ expect(VismaEaccounting::Request.new.api_endpoint).to eq(VismaEaccounting::Request.api_endpoint)
186
+ end
187
+
188
+ it "set proxy on new instances" do
189
+ expect(VismaEaccounting::Request.new.proxy).to eq(VismaEaccounting::Request.proxy)
190
+ end
191
+
192
+ it "set symbolize_keys on new instances" do
193
+ expect(VismaEaccounting::Request.new.symbolize_keys).to eq(VismaEaccounting::Request.symbolize_keys)
194
+ end
195
+
196
+ it "set debug on new instances" do
197
+ expect(VismaEaccounting::Request.new.debug).to eq(VismaEaccounting::Request.debug)
198
+ end
199
+
200
+ it "set faraday_adapter on new instances" do
201
+ expect(VismaEaccounting::Request.new.faraday_adapter).to eq(VismaEaccounting::Request.faraday_adapter)
202
+ end
203
+
204
+ it "set logger on new instances" do
205
+ expect(VismaEaccounting::Request.new.logger).to eq(logger)
206
+ end
207
+ end
208
+
209
+ describe "missing methods" do
210
+ it "respond to .method call on class" do
211
+ expect(VismaEaccounting::Request.method(:customers)).to be_a(Method)
212
+ end
213
+ it "respond to .method call on instance" do
214
+ expect(VismaEaccounting::Request.new.method(:customers)).to be_a(Method)
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'visma_eaccounting/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "visma_eaccounting"
7
+ s.version = VismaEaccounting::VERSION
8
+ s.authors = ["Espen Antonsen", "Amro Mousa"]
9
+ s.homepage = "http://github.com/espen/visma_eaccounting"
10
+
11
+ s.summary = %q{A wrapper for Visma eAccounting API 2.0}
12
+ s.description = %q{A wrapper for Visma eAccounting API 2.0}
13
+ s.license = "MIT"
14
+
15
+ s.rubyforge_project = "visma_eaccounting"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ s.required_ruby_version = '>= 2.0.0'
22
+
23
+ s.add_dependency('faraday', '>= 0.9.1')
24
+ s.add_dependency('multi_json', '>= 1.11.0')
25
+
26
+ s.add_development_dependency 'rake'
27
+ s.add_development_dependency "rspec", "3.5.0"
28
+ s.add_development_dependency 'webmock', '~> 1.21.0'
29
+
30
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: visma_eaccounting
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Espen Antonsen
8
+ - Amro Mousa
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-12-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faraday
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 0.9.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 0.9.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: multi_json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 1.11.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 1.11.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '='
61
+ - !ruby/object:Gem::Version
62
+ version: 3.5.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '='
68
+ - !ruby/object:Gem::Version
69
+ version: 3.5.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: webmock
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 1.21.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 1.21.0
84
+ description: A wrapper for Visma eAccounting API 2.0
85
+ email:
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".document"
91
+ - ".gitignore"
92
+ - ".travis.yml"
93
+ - CHANGELOG.md
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.markdown
97
+ - Rakefile
98
+ - lib/visma_eaccounting.rb
99
+ - lib/visma_eaccounting/api_error.rb
100
+ - lib/visma_eaccounting/api_request.rb
101
+ - lib/visma_eaccounting/request.rb
102
+ - lib/visma_eaccounting/response.rb
103
+ - lib/visma_eaccounting/version.rb
104
+ - lib/visma_eaccounting/visma_eaccounting_error.rb
105
+ - spec/spec_helper.rb
106
+ - spec/visma_eaccounting/api_error_spec.rb
107
+ - spec/visma_eaccounting/api_request_spec.rb
108
+ - spec/visma_eaccounting/visma_eaccounting_spec.rb
109
+ - visma_eaccounting.gemspec
110
+ homepage: http://github.com/espen/visma_eaccounting
111
+ licenses:
112
+ - MIT
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 2.0.0
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project: visma_eaccounting
130
+ rubygems_version: 2.7.3
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: A wrapper for Visma eAccounting API 2.0
134
+ test_files:
135
+ - spec/spec_helper.rb
136
+ - spec/visma_eaccounting/api_error_spec.rb
137
+ - spec/visma_eaccounting/api_request_spec.rb
138
+ - spec/visma_eaccounting/visma_eaccounting_spec.rb