fakturoid 0.1.0

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
+ SHA1:
3
+ metadata.gz: 076c161dacf951eb18acf2852ef982e0105ca544
4
+ data.tar.gz: dadf19899fa9ee0eda8bb8e96ca8e225ac166194
5
+ SHA512:
6
+ metadata.gz: 8b46b7684942b394c3bd00dcd256e5a66ff388737371be5f61441b73b10920fe1cb0197892de2ee79d2433a47a1e33c5974bdc4fbc70383209d003ff98aa5359
7
+ data.tar.gz: 68ebfce58da609f156a85657f8d05057ca7888f0ae703e654f2514e4fb4698dd7b454256faa80fa38bf534a1e1566a8f75daf2b585a2f20c3e20117b4ad47942
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .bundle/
2
+ Gemfile.lock
3
+ coverage/
4
+ doc/
5
+ pkg/
6
+ .DS_Store
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.0
data/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+ ## 0.1.0 (Initial version)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fakturoid.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Eda Riedl
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,262 @@
1
+ # Fakturoid
2
+
3
+ The Fakturoid gem is ruby library for API communication with web based invoicing service [www.fakturoid.cz](https://fakturoid.cz).
4
+ Fakturoid [API documentation](http://docs.fakturoid.apiary.io).
5
+
6
+ [![Circle CI](https://circleci.com/gh/fakturoid/fakturoid-ruby.svg?style=svg)](https://circleci.com/gh/fakturoid/fakturoid-ruby)
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'fakturoid', git: 'https://github.com/fakturoid/fakturoid-ruby.git'
14
+ ```
15
+
16
+ And then run:
17
+
18
+ $ bundle
19
+
20
+ Gem is not officially released and is under construction. So if you want to use it please install it from this repository
21
+ and specify `:ref` option. API of the Fakturoid gem can be still changed.
22
+
23
+ ## Configuration
24
+
25
+ Fakturoid gem is configured within config block placed in `config/initializers/fakturoid.rb`:
26
+
27
+ ```ruby
28
+ Fakturoid.configure do |config|
29
+ config.email = 'yourfakturoid@email.com'
30
+ config.api_key = 'fasdff823fdasWRFKW843ladfjklasdf834'
31
+ config.account = 'applecorp' # former subdomain (first part of URL)
32
+ config.user_agent = 'Name of your app (your@email.com)'
33
+ end
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Account resource
39
+
40
+ To get informations about your account in Fakturoid run following code:
41
+
42
+ ```ruby
43
+ response = Fakturoid::Client::Account.current
44
+ response.status_code # returns response http code
45
+ response.body # contains hash with returned body
46
+ ```
47
+
48
+ Accessing content of returned body:
49
+
50
+ ```ruby
51
+ response.body['name'] # return name of your company
52
+ response.name # alternative way of getting the name of your company
53
+ ```
54
+
55
+ For the list of all returned account fields see the [Account API documentation](http://docs.fakturoid.apiary.io/#account)
56
+
57
+ ### User resource
58
+
59
+ For the information about current user use following code:
60
+
61
+ ```ruby
62
+ response = Fakturoid::Client::User.current
63
+ ```
64
+
65
+ For all the users which belongs to current account:
66
+
67
+ ```ruby
68
+ response = Fakturoid::Client::User.all
69
+ ```
70
+
71
+ If you want to get information about one user which belongs to account use:
72
+
73
+ ```ruby
74
+ response = Fakturoid::Client::User.find(user_id)
75
+ ```
76
+
77
+ For the list of all returned user fields see the [Users API documentation](http://docs.fakturoid.apiary.io/#users)
78
+
79
+ ### Subject resource
80
+
81
+ To get all subjects run (Subjects are paginated by 20 per page):
82
+
83
+ ```ruby
84
+ response = Fakturoid::Client::Subject.all page: 2
85
+ ```
86
+
87
+ Fulltext search subjects:
88
+
89
+ ```ruby
90
+ response = Fakturoid::Client::Subject.search 'Client name'
91
+ ```
92
+
93
+ To find one subject use:
94
+
95
+ ```ruby
96
+ response = Fakturoid::Client::Subject.find subject_id
97
+ ```
98
+
99
+ You can create new subject with:
100
+
101
+ ```ruby
102
+ response = Fakturoid::Client::Subject.create name: 'New client'
103
+ ```
104
+
105
+ To update subject use following code:
106
+
107
+ ```ruby
108
+ response = Fakturoid::Client::Subject.update subject_id, name: 'Updated client'
109
+ ```
110
+
111
+ Delete subject:
112
+
113
+ ```ruby
114
+ Fakturoid::Client::Subject.delete subject_id
115
+ ```
116
+
117
+ For the list of all subject fields and options see the [Subjects API documentation](http://docs.fakturoid.apiary.io/#subjects)
118
+
119
+ ### Invoice resource
120
+
121
+ To get all invoices run (Invoices are paginated by 20 per page):
122
+
123
+ ```ruby
124
+ response = Fakturoid::Client::Invoice.all page: 2
125
+ ```
126
+
127
+ Fulltext search invoices:
128
+
129
+ ```ruby
130
+ response = Fakturoid::Client::Invoice.search 'Client name'
131
+ ```
132
+
133
+ To find one invoice use:
134
+
135
+ ```ruby
136
+ response = Fakturoid::Client::Invoice.find invoice_id
137
+ ```
138
+
139
+ To download invoice in PDF format you can use following code:
140
+
141
+ ```ruby
142
+ response = Fakturoid::Client::Invoice.download_pdf invoice_id
143
+
144
+ File.open '/path/to/file.pdf', 'w' do |f|
145
+ f.write response.body
146
+ end
147
+ ```
148
+
149
+ You can create new invoice with:
150
+
151
+ ```ruby
152
+ invoice = {
153
+ subject_id: 123,
154
+ lines: [
155
+ {
156
+ quantity: 5,
157
+ unit_name: 'kg',
158
+ name: 'Sand',
159
+ unit_price: '100',
160
+ vat_rate: 21
161
+ }
162
+ ]
163
+ }
164
+ response = Fakturoid::Client::Invoice.create invoice
165
+ ```
166
+
167
+ Invoice actions (eg. pay invoice):
168
+
169
+ ```ruby
170
+ response = Fakturoid::Client::Invoice.fire invoice_id, 'pay'
171
+ ```
172
+
173
+ Send invoice with customized message (for more information see [the API Documentation](http://docs.fakturoid.apiary.io/#messages)):
174
+
175
+ ```ruby
176
+ message = {
177
+ email: 'testemail@testemail.cz',
178
+ email_copy: 'some@emailcopy.cz',
179
+ subject: 'I have an invoice for you',
180
+ message: "Hi,\n\nyou can find invoice no. #no# on the following page #link#\n\nHave a nice day"
181
+ }
182
+
183
+ response = Fakturoid::Client::Invoice.deliver_message(181, message)
184
+ response.status_code # => 201
185
+ ```
186
+
187
+ To update invoice use following code:
188
+
189
+ ```ruby
190
+ response = Fakturoid::Client::Invoice.update invoice_id, number: '2015-0015'
191
+ ```
192
+
193
+ Delete invoice:
194
+
195
+ ```ruby
196
+ response = Fakturoid::Client::Invoice.delete invoice_id
197
+ ```
198
+
199
+ For the list of all invoice fields and options see the [Invoices API documentation](http://docs.fakturoid.apiary.io/#invoices)
200
+
201
+ ## Handling error responses
202
+
203
+ The Fakturoid gem raises exceptions if error response is returned from the servers. All exceptions contains following attributes:
204
+
205
+ - `message` - Error description
206
+ - `response_code` - http code of error (only number)
207
+ - `response_body` - response body parsed in the hash
208
+
209
+ <table>
210
+ <thead>
211
+ <tr>
212
+ <th>Error class</th><th>Response code</th><th>Description</th>
213
+ </tr>
214
+ </thead>
215
+ <tbody>
216
+ <tr>
217
+ <td>ContentTypeError</td><td>415 Unsupported Media Type</td><td>Wrong content type</td>
218
+ </tr>
219
+ <tr>
220
+ <td>UserAgentError</td><td>400 Bad Request</td><td>Missing `user_agent` configuration</td>
221
+ </tr>
222
+ <tr>
223
+ <td>PaginationError</td><td>400 Bad Request</td><td>Page with given number does not exist</td>
224
+ </tr>
225
+ <tr>
226
+ <td>AuthenticationError</td><td>401 Unauthorized</td><td>Wrong authentication `email` or `api_key` configuration</td>
227
+ </tr>
228
+ <tr>
229
+ <td>BlockedAccountError</td><td>402 Payment Required</td><td>Fakturoid account is blocked</td>
230
+ </tr>
231
+ <tr>
232
+ <td>RateLimitError</td><td>429 Too Many Requests</td><td>Too many request sent during last 5 minutes</td>
233
+ </tr>
234
+ <tr>
235
+ <td>ReadOnlySiteError</td><td>503 Service Unavailable</td><td>Fakturoid is read only</td>
236
+ </tr>
237
+ <tr>
238
+ <td>RecordNotFoundError</td><td>404 Not Found</td><td>Document with given ID does not exists or current account has read only permission and trying to edit something</td>
239
+ </tr>
240
+ <tr>
241
+ <td>InvalidRecordError</td><td>422 Unprocessable Entity</td><td>Invalid data sent to server</td>
242
+ </tr>
243
+ <tr>
244
+ <td>DestroySubjectError</td><td>403 Forbidden</td><td>Subject has invoices or expenses and cannot be deleted</td>
245
+ </tr>
246
+ <tr>
247
+ <td>SubjectLimitError</td><td>403 Forbidden</td><td>Subject quota reached for adding more subjects upgrade to higher plan</td>
248
+ </tr>
249
+ <tr>
250
+ <td>GeneratorLimitError</td><td>403 Forbidden</td><td>Generator quota reached for adding more recurring generators upgrade to higher plan</td>
251
+ </tr>
252
+ <tr>
253
+ <td>UnsupportedFeatureError</td><td>403 Forbidden</td><td>Feature is not supported in your plan to use this feature upgrade to higher plan</td>
254
+ </tr>
255
+ <tr>
256
+ <td>ClientError</td><td>4XX</td><td>Server returns response code which is not specified above</td>
257
+ </tr>
258
+ <tr>
259
+ <td>ServerError</td><td>5XX</td><td>Server returns response code which is not specified above</td>
260
+ </tr>
261
+ </tbody>
262
+ </table>
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ task default: :test
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.test_files = FileList['test/*_test.rb']
9
+ t.verbose = true
10
+ end
data/fakturoid.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fakturoid/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "fakturoid"
8
+ s.version = Fakturoid::VERSION
9
+ s.authors = ["Eda Riedl", "Lukáš Konarovský"]
10
+ s.email = ["podpora@fakturoid.cz"]
11
+ s.summary = %q{Ruby client for web based invoicing service www.fakturoid.cz}
12
+ s.description = %q{Ruby client for web based invoicing service www.fakturoid.cz}
13
+ s.homepage = "https://github.com/fakturoid/fakturoid-ruby"
14
+ s.license = "MIT"
15
+
16
+ s.files = `git ls-files -z`.split("\x0")
17
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'multi_json'
22
+ s.add_dependency 'faraday'
23
+
24
+ s.add_development_dependency "bundler", "> 1"
25
+ s.add_development_dependency "rake"
26
+ s.add_development_dependency "minitest"
27
+ s.add_development_dependency "shoulda-context"
28
+ s.add_development_dependency "mocha"
29
+ end
data/lib/fakturoid.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'uri'
2
+ require 'multi_json'
3
+ require 'faraday'
4
+
5
+ require 'fakturoid/config'
6
+ require 'fakturoid/connection'
7
+ require 'fakturoid/request'
8
+ require 'fakturoid/response'
9
+ require 'fakturoid/api'
10
+ require 'fakturoid/client'
11
+ require 'fakturoid/version'
12
+ require 'fakturoid/railtie' if defined?(::Rails)
13
+
14
+ module Fakturoid
15
+
16
+ class ApiError < StandardError
17
+ attr_accessor :response_code, :response_body
18
+
19
+ def initialize(message = nil, response_code = nil, response_body = nil)
20
+ super(message)
21
+ self.response_code = response_code
22
+ self.response_body = response_body
23
+ end
24
+ end
25
+
26
+ class ContentTypeError < ApiError; end
27
+ class UserAgentError < ApiError; end
28
+ class AuthenticationError < ApiError; end
29
+ class BlockedAccountError < ApiError; end
30
+ class RateLimitError < ApiError; end
31
+ class ReadOnlySiteError < ApiError; end
32
+ class PaginationError < ApiError; end
33
+
34
+ class RecordNotFoundError < ApiError; end
35
+ class InvalidRecordError < ApiError; end
36
+ class DestroySubjectError < ApiError; end
37
+ class SubjectLimitError < ApiError; end
38
+ class GeneratorLimitError < ApiError; end
39
+ class UnsupportedFeatureError < ApiError; end
40
+
41
+ class ClientError < ApiError; end
42
+ class ServerError < ApiError; end
43
+
44
+ def self.configure(&block)
45
+ Fakturoid::Api.configure(&block)
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ require 'fakturoid/api/arguments'
2
+ require 'fakturoid/api/http_methods'
3
+
4
+ module Fakturoid
5
+ class Api
6
+ extend Arguments
7
+ extend HttpMethods
8
+
9
+ def self.configure(&block)
10
+ @config ||= Fakturoid::Config.new(&block)
11
+ end
12
+
13
+ def self.config
14
+ @config
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module Fakturoid
2
+ class Api
3
+ module Arguments
4
+ def permit_params(params_hash, *permitted_params)
5
+ params_hash.select { |param, value| permitted_params.include?(param.to_sym) }
6
+ end
7
+
8
+ def validate_numerical_id(id)
9
+ raise ArgumentError, "Wrong ID given: #{id}" if !id.is_a?(Integer) && !(id.is_a?(String) && id =~ /\A\d+\z/)
10
+ true
11
+ end
12
+
13
+ def validate_search_query(query)
14
+ raise ArgumentError, 'Query parameter is required' if query.nil? || query.empty?
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module Fakturoid
2
+ class Api
3
+ module HttpMethods
4
+ def get_request(path, params = {})
5
+ Request.new(:get, path, self).call(params)
6
+ end
7
+
8
+ def post_request(path, params = {})
9
+ Request.new(:post, path, self).call(params)
10
+ end
11
+
12
+ def patch_request(path, params = {})
13
+ Request.new(:patch, path, self).call(params)
14
+ end
15
+
16
+ def delete_request(path, params = {})
17
+ Request.new(:delete, path, self).call(params)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ require 'fakturoid/client/account'
2
+ require 'fakturoid/client/bank_account'
3
+ require 'fakturoid/client/user'
4
+ require 'fakturoid/client/subject'
5
+ require 'fakturoid/client/invoice'
6
+ require 'fakturoid/client/expense'
7
+ require 'fakturoid/client/generator'
8
+ require 'fakturoid/client/event'
9
+ require 'fakturoid/client/todo'
@@ -0,0 +1,9 @@
1
+ module Fakturoid
2
+ module Client
3
+ class Account < Fakturoid::Api
4
+ def self.current
5
+ get_request('account.json')
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Fakturoid
2
+ module Client
3
+ class BankAccount < Fakturoid::Api
4
+ def self.all
5
+ get_request('bank_accounts.json')
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Fakturoid
2
+ module Client
3
+ class Event < Fakturoid::Api
4
+ def self.all(params = {})
5
+ request_params = permit_params(params, :page, :since, :subject_id) || {}
6
+
7
+ get_request('events.json', request_params: request_params)
8
+ end
9
+
10
+ def self.paid(params = {})
11
+ request_params = permit_params(params, :page, :since, :subject_id) || {}
12
+
13
+ get_request('events/paid.json', request_params: request_params)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,40 @@
1
+ module Fakturoid
2
+ module Client
3
+ class Expense < Fakturoid::Api
4
+ def self.all(params = {})
5
+ request_params = permit_params(params, :page, :since, :number, :variable_symbol, :status, :subject_id) || {}
6
+
7
+ get_request('expenses.json', request_params: request_params)
8
+ end
9
+
10
+ def self.find(id)
11
+ validate_numerical_id(id)
12
+ get_request("expenses/#{id}.json")
13
+ end
14
+
15
+ def self.search(query)
16
+ validate_search_query(query)
17
+ get_request('expenses/search.json', request_params: { query: query })
18
+ end
19
+
20
+ def self.fire(id, event)
21
+ validate_numerical_id(id)
22
+ post_request("expenses/#{id}/fire.json", request_params: { event: event })
23
+ end
24
+
25
+ def self.create(payload = {})
26
+ post_request('expenses.json', payload: payload)
27
+ end
28
+
29
+ def self.update(id, payload = {})
30
+ validate_numerical_id(id)
31
+ patch_request("expenses/#{id}.json", payload: payload)
32
+ end
33
+
34
+ def self.delete(id)
35
+ validate_numerical_id(id)
36
+ delete_request("expenses/#{id}.json")
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,42 @@
1
+ module Fakturoid
2
+ module Client
3
+ class Generator < Fakturoid::Api
4
+ def self.all(params = {})
5
+ request_params = permit_params(params, :page, :since, :subject_id) || {}
6
+
7
+ get_request('generators.json', request_params: request_params)
8
+ end
9
+
10
+ def self.recurring(params = {})
11
+ request_params = permit_params(params, :page, :since, :subject_id) || {}
12
+
13
+ get_request('generators/recurring.json', request_params: request_params)
14
+ end
15
+
16
+ def self.template(params = {})
17
+ request_params = permit_params(params, :page, :since, :subject_id) || {}
18
+
19
+ get_request('generators/template.json', request_params: request_params)
20
+ end
21
+
22
+ def self.find(id)
23
+ validate_numerical_id(id)
24
+ get_request("generators/#{id}.json")
25
+ end
26
+
27
+ def self.create(payload = {})
28
+ post_request('generators.json', payload: payload)
29
+ end
30
+
31
+ def self.update(id, payload = {})
32
+ validate_numerical_id(id)
33
+ patch_request("generators/#{id}.json", payload: payload)
34
+ end
35
+
36
+ def self.delete(id)
37
+ validate_numerical_id(id)
38
+ delete_request("generators/#{id}.json")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,62 @@
1
+ module Fakturoid
2
+ module Client
3
+ class Invoice < Fakturoid::Api
4
+ def self.all(params = {})
5
+ request_params = permit_params(params, :page, :since, :number, :status, :subject_id) || {}
6
+
7
+ get_request('invoices.json', request_params: request_params)
8
+ end
9
+
10
+ def self.regular(params = {})
11
+ request_params = permit_params(params, :page, :since, :number, :status, :subject_id) || {}
12
+
13
+ get_request('invoices/regular.json', request_params: request_params)
14
+ end
15
+
16
+ def self.proforma(params = {})
17
+ request_params = permit_params(params, :page, :since, :number, :status, :subject_id) || {}
18
+
19
+ get_request('invoices/proforma.json', request_params: request_params)
20
+ end
21
+
22
+ def self.find(id)
23
+ validate_numerical_id(id)
24
+ get_request("invoices/#{id}.json")
25
+ end
26
+
27
+ def self.search(query)
28
+ validate_search_query(query)
29
+ get_request('invoices/search.json', request_params: { query: query })
30
+ end
31
+
32
+ def self.download_pdf(id)
33
+ validate_numerical_id(id)
34
+ get_request("invoices/#{id}/download.pdf", headers: { content_type: 'application/pdf' })
35
+ end
36
+
37
+ def self.fire(id, event)
38
+ validate_numerical_id(id)
39
+ post_request("invoices/#{id}/fire.json", request_params: { event: event })
40
+ end
41
+
42
+ def self.deliver_message(invoice_id, payload = {})
43
+ validate_numerical_id(invoice_id)
44
+ post_request("invoices/#{invoice_id}/message.json", payload: payload)
45
+ end
46
+
47
+ def self.create(payload = {})
48
+ post_request('invoices.json', payload: payload)
49
+ end
50
+
51
+ def self.update(id, payload = {})
52
+ validate_numerical_id(id)
53
+ patch_request("invoices/#{id}.json", payload: payload)
54
+ end
55
+
56
+ def self.delete(id)
57
+ validate_numerical_id(id)
58
+ delete_request("invoices/#{id}.json")
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,35 @@
1
+ module Fakturoid
2
+ module Client
3
+ class Subject < Fakturoid::Api
4
+ def self.all(params = {})
5
+ request_params = permit_params(params, :page, :since, :custom_id) || {}
6
+
7
+ get_request('subjects.json', request_params: request_params)
8
+ end
9
+
10
+ def self.find(id)
11
+ validate_numerical_id(id)
12
+ get_request("subjects/#{id}.json")
13
+ end
14
+
15
+ def self.search(query)
16
+ validate_search_query(query)
17
+ get_request('subjects/search.json', request_params: { query: query })
18
+ end
19
+
20
+ def self.create(payload = {})
21
+ post_request('subjects.json', payload: payload)
22
+ end
23
+
24
+ def self.update(id, payload = {})
25
+ validate_numerical_id(id)
26
+ patch_request("subjects/#{id}.json", payload: payload)
27
+ end
28
+
29
+ def self.delete(id)
30
+ validate_numerical_id(id)
31
+ delete_request("subjects/#{id}.json")
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ module Fakturoid
2
+ module Client
3
+ class Todo < Fakturoid::Api
4
+ def self.all(params = {})
5
+ request_params = permit_params(params, :page, :since) || {}
6
+
7
+ get_request('todos.json', request_params: request_params)
8
+ end
9
+
10
+ def self.toggle_completion(id)
11
+ validate_numerical_id(id)
12
+ post_request("todos/#{id}/toggle_completion.json")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module Fakturoid
2
+ module Client
3
+ class User < Api
4
+ def self.current
5
+ get_request('user.json', url: Fakturoid::Api.config.endpoint_without_account)
6
+ end
7
+
8
+ def self.find(id)
9
+ validate_numerical_id(id)
10
+ get_request("users/#{id}.json")
11
+ end
12
+
13
+ def self.all
14
+ get_request('users.json')
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ module Fakturoid
2
+ class Config
3
+ attr_accessor :email, :api_key, :account
4
+ attr_writer :user_agent
5
+
6
+ ENDPOINT = 'https://app.fakturoid.cz/api/v2'
7
+
8
+ def initialize(&block)
9
+ yield self
10
+ end
11
+
12
+ def user_agent
13
+ if @user_agent.nil? || @user_agent.empty?
14
+ "Fakturoid ruby gem (#{email})"
15
+ else
16
+ @user_agent
17
+ end
18
+ end
19
+
20
+ def endpoint
21
+ "#{ENDPOINT}/accounts/#{account}"
22
+ end
23
+
24
+ def endpoint_without_account
25
+ ENDPOINT
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ module Fakturoid
2
+ module Connection
3
+
4
+ def default_options(options = {})
5
+ content_type = options[:headers] && options[:headers][:content_type]
6
+ {
7
+ headers: {
8
+ content_type: content_type || 'application/json',
9
+ user_agent: Fakturoid::Api.config.user_agent
10
+ },
11
+ url: options[:url] || Fakturoid::Api.config.endpoint
12
+ }
13
+ end
14
+
15
+ def connection(options = {})
16
+ @connection = Faraday.new default_options(options)
17
+ @connection.basic_auth(Fakturoid::Api.config.email, Fakturoid::Api.config.api_key)
18
+
19
+ @connection
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+ module Fakturoid
2
+ class Railtie < Rails::Railtie
3
+ end
4
+ end
@@ -0,0 +1,28 @@
1
+ module Fakturoid
2
+ class Request
3
+ include Connection
4
+
5
+ attr_reader :method, :path, :caller
6
+ HTTP_METHODS = [:get, :post, :patch, :delete]
7
+
8
+ def initialize(method, path, caller)
9
+ @method = method
10
+ @path = path
11
+ @caller = caller
12
+ end
13
+
14
+ def call(params = {})
15
+ unless HTTP_METHODS.include?(method.to_sym)
16
+ raise ArgumentError, "Unknown http method: #{method}"
17
+ end
18
+ request_params = params[:request_params] || {}
19
+
20
+ http_connection = connection(params)
21
+ response = http_connection.send(method) do |req|
22
+ req.url path, request_params
23
+ req.body = MultiJson.dump(params[:payload]) if params.key?(:payload)
24
+ end
25
+ Response.new(response, caller, method)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,70 @@
1
+ module Fakturoid
2
+ class Response
3
+ attr_reader :response, :caller, :env, :body, :request_method
4
+
5
+ def initialize(faraday_response, caller, request_method)
6
+ @response = faraday_response
7
+ @caller = caller
8
+ @env = faraday_response.env
9
+ @request_method = request_method.to_sym
10
+
11
+ if !(env.body.nil? || env.body.empty? || (json? && env.body =~ /\A\s+\z/))
12
+ @body = json? ? MultiJson.load(env.body) : env.body
13
+ end
14
+ handle_response
15
+ end
16
+
17
+ def method_missing(method, *args, &block)
18
+ if body && body.is_a?(Hash) && body.key?(method.to_s)
19
+ body[method.to_s]
20
+ else
21
+ super
22
+ end
23
+ end
24
+
25
+ def status_code
26
+ env['status']
27
+ end
28
+
29
+ def json?
30
+ env.request_headers['Content-Type'] == 'application/json'
31
+ end
32
+
33
+ def headers
34
+ env.response_headers
35
+ end
36
+
37
+ def inspect
38
+ "#<#{self.class.name}:#{object_id} @body=\"#{self.body}\" @status_code=\"#{status_code}\">"
39
+ end
40
+
41
+ private
42
+
43
+ def handle_response
44
+ case status_code
45
+ when 400
46
+ raise error(UserAgentError, 'User-Agent header missing') if env.request_headers['User-Agent'].nil? || env.request_headers['User-Agent'].empty?
47
+ raise error(PaginationError, 'Page does not exist')
48
+ when 401 then raise error(AuthenticationError, 'Authentification failed')
49
+ when 402 then raise error(BlockedAccountError, 'Account is blocked')
50
+ when 403 then
51
+ raise error(DestroySubjectError, 'Cannot destroy subject with invoices') if caller == Client::Subject && request_method == :delete
52
+ raise error(SubjectLimitError, 'Subject limit for account reached') if caller == Client::Subject && request_method == :post
53
+ raise error(GeneratorLimitError, 'Recurring generator limit for account reached') if caller == Client::Generator
54
+ raise error(UnsupportedFeatureError, 'Feature unavailable for account plan')
55
+ when 404 then raise error(RecordNotFoundError, 'Record not found')
56
+ when 415 then raise error(ContentTypeError, 'Unsupported Content-Type')
57
+ when 422 then raise error(InvalidRecordError, 'Invalid record')
58
+ when 429 then raise error(RateLimitError, 'Rate limit reached')
59
+ when 503 then raise error(ReadOnlySiteError, 'Fakturoid is in read only state')
60
+ else
61
+ raise error(ServerError, 'Server error') if status_code >= 500
62
+ raise error(ClientError, 'Client error') if status_code >= 400
63
+ end
64
+ end
65
+
66
+ def error(klass, message = nil)
67
+ klass.new message, status_code, body
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module Fakturoid
2
+ VERSION = '0.1.0'
3
+ end
data/test/api_test.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+ class Fakturoid::ApiTest < Fakturoid::TestCase
4
+ should "permit only required arguments" do
5
+ hash = { page: 4, number: '2015-0015', account: 15 }
6
+ permitted_params = Fakturoid::Api.permit_params(hash, :page, :number, :status)
7
+ assert_equal({ page: 4, number: '2015-0015' }, permitted_params)
8
+ end
9
+
10
+ should "raise argument error if id is in wrong format" do
11
+ assert_raises(ArgumentError) { Fakturoid::Api.validate_numerical_id(nil) }
12
+ assert_raises(ArgumentError) { Fakturoid::Api.validate_numerical_id("nil") }
13
+ assert Fakturoid::Api.validate_numerical_id(15)
14
+ assert Fakturoid::Api.validate_numerical_id("15")
15
+ end
16
+
17
+ should "raise argument error if search query is not given" do
18
+ assert_raises(ArgumentError) { Fakturoid::Api.validate_search_query(nil) }
19
+ assert_raises(ArgumentError) { Fakturoid::Api.validate_search_query("") }
20
+ assert Fakturoid::Api.validate_search_query("Company name")
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ require 'test_helper'
2
+
3
+ class Fakturoid::ConfigTest < Fakturoid::TestCase
4
+ should "configure with block param" do
5
+ config = Fakturoid::Config.new do |config|
6
+ config.email = 'test@email.cz'
7
+ config.api_key = 'XXXXXXXXXXX'
8
+ config.account = 'testaccount'
9
+ config.user_agent = 'My test app (test@email.cz)'
10
+ end
11
+
12
+ assert_equal 'test@email.cz', config.email
13
+ assert_equal 'XXXXXXXXXXX', config.api_key
14
+ assert_equal 'testaccount', config.account
15
+ assert_equal 'My test app (test@email.cz)', config.user_agent
16
+ end
17
+
18
+ should "use default user agent" do
19
+ config = Fakturoid::Config.new do |config|
20
+ config.email = 'test@email.cz'
21
+ config.api_key = 'XXXXXXXXXXX'
22
+ config.account = 'testaccount'
23
+ end
24
+
25
+ assert_equal 'Fakturoid ruby gem (test@email.cz)', config.user_agent
26
+ end
27
+
28
+ should "return correct endpoints" do
29
+ config = Fakturoid::Config.new do |config|
30
+ config.email = 'test@email.cz'
31
+ config.api_key = 'XXXXXXXXXXX'
32
+ config.account = 'testaccount'
33
+ end
34
+
35
+ assert_equal 'https://app.fakturoid.cz/api/v2/accounts/testaccount', config.endpoint
36
+ assert_equal 'https://app.fakturoid.cz/api/v2', config.endpoint_without_account
37
+ end
38
+ end
@@ -0,0 +1,81 @@
1
+ {
2
+ "id": 5,
3
+ "proforma": false,
4
+ "number": "2012-0004",
5
+ "variable_symbol": "20120004",
6
+ "your_name": "Alexandr Hejsek",
7
+ "your_street": "Hopsinkov\u00e1 14",
8
+ "your_street2": null,
9
+ "your_city": "Praha",
10
+ "your_zip": "10000",
11
+ "your_country": "CZ",
12
+ "your_registration_no": "87654321",
13
+ "your_vat_no": "CZ87654321",
14
+ "client_name": "Microsoft a. s.",
15
+ "client_street": "Trojanova 1216/46",
16
+ "client_street2": null,
17
+ "client_city": "Praha",
18
+ "client_zip": "11000",
19
+ "client_country": "CZ",
20
+ "client_registration_no": "28444501",
21
+ "client_vat_no": "CZ28444501",
22
+ "subject_id": 4,
23
+ "generator_id": 4,
24
+ "related_id": null,
25
+ "correction": false,
26
+ "correction_id": null,
27
+ "token": "udDTG8Q88M",
28
+ "status": "paid",
29
+ "order_number": null,
30
+ "issued_on": "2011-10-13",
31
+ "taxable_fulfillment_due": "2011-10-13",
32
+ "due": 10,
33
+ "due_on": "2011-10-23",
34
+ "sent_at": null,
35
+ "paid_at": "2011-10-20T12:11:37+02:00",
36
+ "reminder_sent_at": null,
37
+ "accepted_at": null,
38
+ "cancelled_at": null,
39
+ "note": null,
40
+ "footer_note": null,
41
+ "bank_account": "1234/1234",
42
+ "iban": null,
43
+ "swift_bic": null,
44
+ "payment_method": "bank",
45
+ "currency": "CZK",
46
+ "exchange_rate": "1.0",
47
+ "language": "cz",
48
+ "transferred_tax_liability": false,
49
+ "vat_price_mode": "without_vat",
50
+ "subtotal": "40000.0",
51
+ "total": "48400.0",
52
+ "native_subtotal": "40000.0",
53
+ "native_total": "48400.0",
54
+ "lines": [
55
+ {
56
+ "id": 1234,
57
+ "name": "PC",
58
+ "quantity": "1.0",
59
+ "unit_name": "",
60
+ "unit_price": "20000.0",
61
+ "vat_rate": 21,
62
+ "unit_price_without_vat": "20000.0",
63
+ "unit_price_with_vat": "24200.0"
64
+ },
65
+ {
66
+ "id": 1235,
67
+ "name": "Notebook",
68
+ "quantity": "1.0",
69
+ "unit_name": "",
70
+ "unit_price": "20000.0",
71
+ "vat_rate": 21,
72
+ "unit_price_without_vat": "20000.0",
73
+ "unit_price_with_vat": "24200.0"
74
+ }
75
+ ],
76
+ "html_url": "https://app.fakturoid.cz/applecorp/invoices/9",
77
+ "public_html_url": "https://app.fakturoid.cz/applecorp/p/udDTG8Q88M/2012-0004",
78
+ "url": "https://app.fakturoid.cz/api/v2/accounts/applecorp/invoices/9.json",
79
+ "subject_url": "https://app.fakturoid.cz/api/v2/accounts/applecorp/subjects/4.json",
80
+ "updated_at": "2012-05-13T12:11:37+02:00"
81
+ }
Binary file
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ class Fakturoid::RequestTest < Fakturoid::TestCase
4
+ should "should return pdf" do
5
+ pdf = load_fixture('invoice.pdf')
6
+ test_connection = Faraday.new do |builder|
7
+ builder.adapter :test do |stub|
8
+ stub.get('invoices/5/download.pdf') { |env| [ 200, {content_type: 'application/pdf'}, pdf ]}
9
+ end
10
+ builder.headers = { content_type: 'applicatoin/pdf' }
11
+ end
12
+ Fakturoid::Request.any_instance.stubs(:connection).returns(test_connection)
13
+
14
+ response = Fakturoid::Request.new(:get, 'invoices/5/download.pdf', Fakturoid::Client::Invoice).call
15
+ assert !response.json?
16
+ assert_raises(NoMethodError) { response.name }
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ require 'minitest/autorun'
2
+ require 'mocha/setup'
3
+ require 'shoulda-context'
4
+ require 'pathname'
5
+ require 'fakturoid'
6
+
7
+ module Fakturoid
8
+ class TestCase < Minitest::Test
9
+ def test_path
10
+ Pathname.new(File.dirname(__FILE__))
11
+ end
12
+
13
+ def load_fixture(file_name)
14
+ File.read(test_path.join('fixtures', file_name))
15
+ end
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fakturoid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Eda Riedl
8
+ - Lukáš Konarovský
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-02-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: multi_json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: faraday
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">"
47
+ - !ruby/object:Gem::Version
48
+ version: '1'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">"
54
+ - !ruby/object:Gem::Version
55
+ version: '1'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: minitest
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: shoulda-context
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: mocha
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ description: Ruby client for web based invoicing service www.fakturoid.cz
113
+ email:
114
+ - podpora@fakturoid.cz
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".ruby-version"
121
+ - CHANGELOG.md
122
+ - Gemfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - fakturoid.gemspec
127
+ - lib/fakturoid.rb
128
+ - lib/fakturoid/api.rb
129
+ - lib/fakturoid/api/arguments.rb
130
+ - lib/fakturoid/api/http_methods.rb
131
+ - lib/fakturoid/client.rb
132
+ - lib/fakturoid/client/account.rb
133
+ - lib/fakturoid/client/bank_account.rb
134
+ - lib/fakturoid/client/event.rb
135
+ - lib/fakturoid/client/expense.rb
136
+ - lib/fakturoid/client/generator.rb
137
+ - lib/fakturoid/client/invoice.rb
138
+ - lib/fakturoid/client/subject.rb
139
+ - lib/fakturoid/client/todo.rb
140
+ - lib/fakturoid/client/user.rb
141
+ - lib/fakturoid/config.rb
142
+ - lib/fakturoid/connection.rb
143
+ - lib/fakturoid/railtie.rb
144
+ - lib/fakturoid/request.rb
145
+ - lib/fakturoid/response.rb
146
+ - lib/fakturoid/version.rb
147
+ - test/api_test.rb
148
+ - test/config_test.rb
149
+ - test/fixtures/invoice.json
150
+ - test/fixtures/invoice.pdf
151
+ - test/request_test.rb
152
+ - test/test_helper.rb
153
+ homepage: https://github.com/fakturoid/fakturoid-ruby
154
+ licenses:
155
+ - MIT
156
+ metadata: {}
157
+ post_install_message:
158
+ rdoc_options: []
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ requirements: []
172
+ rubyforge_project:
173
+ rubygems_version: 2.4.5
174
+ signing_key:
175
+ specification_version: 4
176
+ summary: Ruby client for web based invoicing service www.fakturoid.cz
177
+ test_files:
178
+ - test/api_test.rb
179
+ - test/config_test.rb
180
+ - test/fixtures/invoice.json
181
+ - test/fixtures/invoice.pdf
182
+ - test/request_test.rb
183
+ - test/test_helper.rb