fakturoid 0.5.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -10
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +15 -0
  5. data/README.md +540 -145
  6. data/Rakefile +3 -1
  7. data/fakturoid.gemspec +36 -25
  8. data/lib/fakturoid/api/account.rb +13 -0
  9. data/lib/fakturoid/api/bank_account.rb +13 -0
  10. data/lib/fakturoid/api/base.rb +18 -0
  11. data/lib/fakturoid/api/event.rb +23 -0
  12. data/lib/fakturoid/api/expense.rb +55 -0
  13. data/lib/fakturoid/api/expense_payment.rb +20 -0
  14. data/lib/fakturoid/api/generator.rb +36 -0
  15. data/lib/fakturoid/api/inbox_file.rb +34 -0
  16. data/lib/fakturoid/api/inventory_item.rb +66 -0
  17. data/lib/fakturoid/api/inventory_move.rb +40 -0
  18. data/lib/fakturoid/api/invoice.rb +62 -0
  19. data/lib/fakturoid/api/invoice_message.rb +14 -0
  20. data/lib/fakturoid/api/invoice_payment.rb +26 -0
  21. data/lib/fakturoid/api/number_format.rb +13 -0
  22. data/lib/fakturoid/api/recurring_generator.rb +36 -0
  23. data/lib/fakturoid/api/subject.rb +42 -0
  24. data/lib/fakturoid/api/todo.rb +20 -0
  25. data/lib/fakturoid/api/user.rb +17 -0
  26. data/lib/fakturoid/api/webhook.rb +34 -0
  27. data/lib/fakturoid/api.rb +89 -9
  28. data/lib/fakturoid/client.rb +46 -12
  29. data/lib/fakturoid/config.rb +69 -12
  30. data/lib/fakturoid/oauth/access_token_service.rb +46 -0
  31. data/lib/fakturoid/oauth/credentials.rb +63 -0
  32. data/lib/fakturoid/oauth/flow/authorization_code.rb +53 -0
  33. data/lib/fakturoid/oauth/flow/base.rb +42 -0
  34. data/lib/fakturoid/oauth/flow/client_credentials.rb +27 -0
  35. data/lib/fakturoid/oauth/flow.rb +5 -0
  36. data/lib/fakturoid/oauth/request/api.rb +11 -0
  37. data/lib/fakturoid/oauth/request/base.rb +60 -0
  38. data/lib/fakturoid/oauth/request/oauth.rb +24 -0
  39. data/lib/fakturoid/oauth/request.rb +5 -0
  40. data/lib/fakturoid/oauth/token_response.rb +56 -0
  41. data/lib/fakturoid/oauth.rb +39 -0
  42. data/lib/fakturoid/response.rb +8 -20
  43. data/lib/fakturoid/utils.rb +27 -0
  44. data/lib/fakturoid/version.rb +1 -1
  45. data/lib/fakturoid.rb +22 -22
  46. metadata +48 -53
  47. data/.github/workflows/rubocop.yml +0 -20
  48. data/.github/workflows/tests.yml +0 -27
  49. data/.gitignore +0 -7
  50. data/Gemfile +0 -6
  51. data/lib/fakturoid/api/arguments.rb +0 -21
  52. data/lib/fakturoid/api/http_methods.rb +0 -23
  53. data/lib/fakturoid/client/account.rb +0 -11
  54. data/lib/fakturoid/client/bank_account.rb +0 -11
  55. data/lib/fakturoid/client/event.rb +0 -19
  56. data/lib/fakturoid/client/expense.rb +0 -49
  57. data/lib/fakturoid/client/generator.rb +0 -44
  58. data/lib/fakturoid/client/inventory_items.rb +0 -59
  59. data/lib/fakturoid/client/inventory_moves.rb +0 -36
  60. data/lib/fakturoid/client/invoice.rb +0 -73
  61. data/lib/fakturoid/client/number_format.rb +0 -11
  62. data/lib/fakturoid/client/subject.rb +0 -41
  63. data/lib/fakturoid/client/todo.rb +0 -18
  64. data/lib/fakturoid/client/user.rb +0 -20
  65. data/lib/fakturoid/connection.rb +0 -30
  66. data/lib/fakturoid/request.rb +0 -31
  67. data/test/api_test.rb +0 -24
  68. data/test/config_test.rb +0 -40
  69. data/test/fixtures/blocked_account.json +0 -8
  70. data/test/fixtures/invoice.json +0 -81
  71. data/test/fixtures/invoice.pdf +0 -0
  72. data/test/fixtures/invoice_error.json +0 -7
  73. data/test/fixtures/subjects.json +0 -52
  74. data/test/request_test.rb +0 -20
  75. data/test/response_test.rb +0 -189
  76. data/test/test_helper.rb +0 -19
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Fakturoid
2
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](https://fakturoid.docs.apiary.io/).
3
+ The Fakturoid gem is Ruby library for API communication with web based invoicing service [www.fakturoid.cz](https://www.fakturoid.cz/).
4
+
5
+ Fakturoid [API documentation](https://www.fakturoid.cz/api/v3).
5
6
 
6
7
  [![Gem Version](https://badge.fury.io/rb/fakturoid.svg)](http://badge.fury.io/rb/fakturoid)
7
8
  [![Tests](https://github.com/fakturoid/fakturoid-ruby/actions/workflows/tests.yml/badge.svg)](https://github.com/fakturoid/fakturoid-ruby/actions/workflows/tests.yml)
@@ -17,148 +18,260 @@ gem "fakturoid"
17
18
 
18
19
  And then run:
19
20
 
20
- $ bundle
21
+ ```sh
22
+ bundle
23
+ ```
24
+
25
+ ## Gem Versions
26
+
27
+ | Gem version | Fakturoid API | Supported Ruby |
28
+ |-------------|---------------------------------------------|----------------|
29
+ | `1.x` | [API v3](https://www.fakturoid.cz/api/v3) | `>=2.7.0` |
30
+ | `0.x` | [API v2](https://fakturoid.docs.apiary.io/) | `>=2.7.0` |
21
31
 
22
32
  ## Configuration
23
33
 
24
- Fakturoid gem is configured within config block placed in `config/initializers/fakturoid.rb`:
34
+ ### Authorization with OAuth 2.0
35
+
36
+ #### Authorization Code Flow
37
+
38
+ Authorization using OAuth takes place in several steps. We use data obtained from the developer portal as client ID and
39
+ client secret (Settings → Connect other apps → OAuth 2 for app developers).
40
+
41
+ First, we offer the user a URL address where he enters his login information. We obtain this using the following method
42
+ (you can place it in an intializer `config/initializers/fakturoid.rb`):
25
43
 
26
44
  ```ruby
27
45
  Fakturoid.configure do |config|
28
- config.email = "yourfakturoid@email.com"
29
- config.api_key = "fasdff823fdasWRFKW843ladfjklasdf834"
30
- config.account = "applecorp" # former subdomain (first part of URL)
31
- config.user_agent = "Name of your app (your@email.com)"
46
+ config.email = "yourfakturoid@email.com"
47
+ config.account = "{fakturoid-account-slug}" # You can also set `account` dynamically later.
48
+ config.user_agent = "Name of your app (your@email.com)"
49
+ config.client_id = "{fakturoid-client-id}"
50
+ config.client_secret = "{fakturoid-client-secret}"
51
+ config.redirect_uri = "{your-redirect-uri}"
52
+ config.oauth_flow = "authorization_code"
32
53
  end
33
54
  ```
34
55
 
35
- ## Usage
56
+ Create a client and let the user come to our OAuth login page:
57
+
58
+ ```ruby
59
+ client = Fakturoid.client
36
60
 
37
- ### Account resource
61
+ # To be rendered on a web page. State is optional.
62
+ link_to client.authorization_uri, "Enable Fakturoid Integration"
63
+ link_to client.authorization_uri(state: "abcd1234"), "Enable Fakturoid Integration"
64
+ ```
38
65
 
39
- To get information about your account in Fakturoid run following code:
66
+ After entering the login data, the user is redirected to the specified redirect URI and with the code with which we
67
+ obtain his credentials. We process the code as follows:
40
68
 
41
69
  ```ruby
42
- response = Fakturoid::Client::Account.current
43
- response.status_code # returns response http code
44
- response.body # contains hash with returned body
70
+ client.authorize(code: params[:code])
45
71
  ```
46
72
 
47
- Accessing content of returned body:
73
+ Credentials are now established in the object instance and we can send queries to the Fakturoid API.
48
74
 
49
75
  ```ruby
50
- response.body["name"] # return name of your company
51
- response.name # alternative way of getting the name of your company
76
+ pp client.credentials.as_json
52
77
  ```
53
78
 
54
- For the list of all returned account fields see the [Account API documentation](https://fakturoid.docs.apiary.io/#reference/account)
79
+ Credentials can also be set manually (eg. loaded from a database):
55
80
 
56
- ### User resource
81
+ ```ruby
82
+ client.credentials = {
83
+ access_token: "1db22484a6d6256e7942158d216157d075ab6e7b583bd16416181ca6c4ac180167acd8d599bd123d", # Example
84
+ refresh_token: "5682a4bc6254d85934a03931ed5e235e0f81bca64aef054fa0049d8c953eab919ba67bd8ceb532d7",
85
+ expires_at: "2024-03-01T12:42:40+01:00", # This also accepts `Time` or `DateTime` object.
86
+ token_type: "Bearer"
87
+ }
88
+ ```
57
89
 
58
- For the information about current user use following code:
90
+ Don't forget to update your credentials after an access token refresh:
59
91
 
60
92
  ```ruby
61
- response = Fakturoid::Client::User.current
93
+ client.credentials_updated_callback do |credentials|
94
+ # Store new credentials into database.
95
+ pp client.credentials.as_json
96
+ end
62
97
  ```
63
98
 
64
- For all the users which belongs to current account:
99
+ You may need to set account slug dynamically:
65
100
 
66
101
  ```ruby
67
- response = Fakturoid::Client::User.all
102
+ client.account = client.users.current.body["accounts"].first["slug"]
68
103
  ```
69
104
 
70
- If you want to get information about one user which belongs to account use:
105
+ And if you need to create a separate client for a different account:
71
106
 
72
107
  ```ruby
73
- response = Fakturoid::Client::User.find(user_id)
108
+ client = Fakturoid::Client.new(account: "{another-fakturoid-account-slug}")
74
109
  ```
75
110
 
76
- For the list of all returned user fields see the [Users API documentation](https://fakturoid.docs.apiary.io/#reference/users)
111
+ Revoke access altogether (works in both flows):
77
112
 
78
- ### Number Format resource
113
+ ```ruby
114
+ client.revoke_access
115
+ ```
79
116
 
80
- For the list of invoice number formats which belong to the current account:
117
+ #### Client Credentials Flow
81
118
 
82
119
  ```ruby
83
- response = Fakturoid::Client::NumberFormat.invoices
120
+ Fakturoid.configure do |config|
121
+ config.email = "yourfakturoid@email.com"
122
+ config.account = "{fakturoid-account-slug}"
123
+ config.user_agent = "Name of your app (your@email.com)"
124
+ config.client_id = "{fakturoid-client-id}"
125
+ config.client_secret = "{fakturoid-client-secret}"
126
+ config.oauth_flow = "client_credentials"
127
+ end
84
128
  ```
85
129
 
86
- For the list of all returned user fields see the [Number formats API documentation](https://fakturoid.docs.apiary.io/#reference/number-formats)
130
+ Credentials can be set and stored the same way as above just without a refresh token.
131
+
132
+ ## Usage
133
+
134
+ Almost all resources that return a list of things are paginated by 40 per page. You can specify the page number
135
+ by passing a `page` parameter: `client.some_resource.all(page: 2)`.
87
136
 
88
- ### Subject resource
137
+ ### [User Resource](https://www.fakturoid.cz/api/v3/users)
89
138
 
90
- To get all subjects run (Subjects are paginated by 20 per page):
139
+ Get current user information along with a list of accounts he/she has access to
91
140
 
92
141
  ```ruby
93
- response = Fakturoid::Client::Subject.all(page: 2)
142
+ response = client.users.current
143
+ response.status_code # Returns response HTTP code.
144
+ response.body # Contains hash with returned body (JSON is parsed automatically).
94
145
  ```
95
146
 
96
- Fulltext search subjects:
147
+ Accessing content of returned body:
97
148
 
98
149
  ```ruby
99
- response = Fakturoid::Client::Subject.search("Client name")
150
+ response.body["name"] # Return name of your company.
151
+ response.name # Alternative way of getting the name of your company.
100
152
  ```
101
153
 
102
- To find one subject use:
154
+ Get a list of all account users:
103
155
 
104
156
  ```ruby
105
- response = Fakturoid::Client::Subject.find(subject_id)
157
+ response = client.users.all
106
158
  ```
107
159
 
108
- You can create new subject with:
160
+ ### [Account Resource](https://www.fakturoid.cz/api/v3/account)
161
+
162
+ Get Fakturoid account information:
109
163
 
110
164
  ```ruby
111
- response = Fakturoid::Client::Subject.create(name: "New client")
165
+ response = client.account.current
112
166
  ```
113
167
 
114
- To update subject use following code:
168
+ ### [Bank Account Resource](https://www.fakturoid.cz/api/v3/bank-accounts)
169
+
170
+ Get a list of bank accounts for current account:
115
171
 
116
172
  ```ruby
117
- response = Fakturoid::Client::Subject.update(subject_id, name: "Updated client")
173
+ response = client.bank_accounts.all
118
174
  ```
119
175
 
120
- Delete subject:
176
+ ### [Number Format Resource](https://www.fakturoid.cz/api/v3/number-formats)
177
+
178
+ Get a list of invoice number formats for current account:
121
179
 
122
180
  ```ruby
123
- Fakturoid::Client::Subject.delete subject_id
181
+ response = client.number_formats.invoices
124
182
  ```
125
183
 
126
- For the list of all subject fields and options see the [Subjects API documentation](https://fakturoid.docs.apiary.io/#reference/subjects)
184
+ ### [Subject Resource](https://www.fakturoid.cz/api/v3/subjects)
127
185
 
128
- ### Invoice resource
186
+ Get a list of subjects:
129
187
 
130
- To get all invoices run (Invoices are paginated by 20 per page):
188
+ ```ruby
189
+ response = client.subjects.all(page: 2)
190
+ ```
191
+
192
+ Fulltext search:
193
+
194
+ ```ruby
195
+ response = client.subjects.search(query: "Client name")
196
+ ```
197
+
198
+ Get a specific subject:
131
199
 
132
200
  ```ruby
133
- response = Fakturoid::Client::Invoice.all(page: 2)
201
+ response = client.subjects.find(subject_id)
134
202
  ```
135
203
 
136
- Fulltext search invoices:
204
+ Create a new subject:
137
205
 
138
206
  ```ruby
139
- response = Fakturoid::Client::Invoice.search("Client name")
207
+ response = client.subjects.create(name: "New client")
140
208
  ```
141
209
 
142
- To find one invoice use:
210
+ Update a subject:
143
211
 
144
212
  ```ruby
145
- response = Fakturoid::Client::Invoice.find(invoice_id)
213
+ response = client.subjects.update(subject_id, name: "Updated client")
146
214
  ```
147
215
 
148
- To download invoice in PDF format you can use following code:
216
+ Delete a subject:
149
217
 
150
218
  ```ruby
151
- response = Fakturoid::Client::Invoice.download_pdf(invoice_id)
219
+ client.subjects.delete(subject_id)
220
+ ```
221
+
222
+ ### [Invoice Resource](https://www.fakturoid.cz/api/v3/invoices)
223
+
224
+ Get a list of invoices:
225
+
226
+ ```ruby
227
+ response = client.invoices.all
228
+ ```
229
+
230
+ Fulltext search:
231
+
232
+ ```ruby
233
+ response = client.invoices.search(query: "Client name")
234
+ response = client.invoices.search(tags: "Housing")
235
+ response = client.invoices.search(tags: ["Housing", "Rent"])
236
+ response = client.invoices.search(query: "Client name", tags: ["Housing"])
237
+ ```
238
+
239
+ Get invoice details:
240
+
241
+ ```ruby
242
+ response = client.invoices.find(invoice_id)
243
+ ```
244
+
245
+ Download invoice in PDF format:
246
+
247
+ ```ruby
248
+ response = client.invoices.download_pdf(invoice_id)
152
249
 
153
250
  File.open("/path/to/file.pdf", "wb") do |f|
154
251
  f.write(response.body)
155
252
  end
156
253
  ```
157
254
 
158
- You can create new invoice with:
255
+ Download an attachment:
256
+
257
+ ```ruby
258
+ response = client.invoices.download_attachment(invoice_id, attachment_id)
259
+
260
+ File.open("/path/to/attachment.pdf", "wb") do |f|
261
+ f.write(response.body)
262
+ end
263
+ ```
264
+
265
+ Invoice actions (eg. lock invoice, cancel, etc., full list is in the API documentation):
159
266
 
160
267
  ```ruby
161
- invoice = {
268
+ response = client.invoices.fire(invoice_id, "lock")
269
+ ```
270
+
271
+ Create an invoice:
272
+
273
+ ```ruby
274
+ data = {
162
275
  subject_id: 123,
163
276
  lines: [
164
277
  {
@@ -170,79 +283,222 @@ invoice = {
170
283
  }
171
284
  ]
172
285
  }
173
- response = Fakturoid::Client::Invoice.create(invoice)
286
+ response = client.invoices.create(data)
287
+ ```
288
+
289
+ Update an invoice:
290
+
291
+ ```ruby
292
+ response = client.invoices.update(invoice_id, number: "2015-0015")
174
293
  ```
175
294
 
176
- Invoice actions (eg. pay invoice):
295
+ Delete an invoice:
177
296
 
178
297
  ```ruby
179
- response = Fakturoid::Client::Invoice.fire(invoice_id, "pay")
298
+ response = client.invoices.delete(invoice_id)
180
299
  ```
181
300
 
182
- Send invoice with customized message (for more information see [the API Documentation](https://fakturoid.docs.apiary.io/#reference/messages)):
301
+ ### [Invoice Payment Resource](https://www.fakturoid.cz/api/v3/invoice-payments)
302
+
303
+ Create an invoice payment:
183
304
 
184
305
  ```ruby
185
- message = {
306
+ response = client.invoice_payments.create(invoice_id, paid_on: Date.today)
307
+ response = client.invoice_payments.create(invoice_id, amount: "500")
308
+ ````
309
+
310
+ Create a tax document for a payment:
311
+
312
+ ```ruby
313
+ response = client.invoice_payments.create_tax_document(invoice_id, payment_id)
314
+ tax_document_response = client.invoices.find(response.tax_document_id)
315
+ ````
316
+
317
+ Delete a payment:
318
+
319
+ ```ruby
320
+ response = client.invoice_payments.delete(invoice_id, payment_id)
321
+ ```
322
+
323
+ ### [Invoice Message Resource](https://www.fakturoid.cz/api/v3/invoice-messages)
324
+
325
+ Send a message to the client (you can use more variables in the `message`, full list is in the API documentation):
326
+
327
+ ```ruby
328
+ data = {
186
329
  email: "testemail@testemail.cz",
187
330
  email_copy: "some@emailcopy.cz",
188
331
  subject: "I have an invoice for you",
189
332
  message: "Hi,\n\nyou can find invoice no. #no# on the following page #link#\n\nHave a nice day"
190
333
  }
191
334
 
192
- response = Fakturoid::Client::Invoice.deliver_message(181, message)
193
- response.status_code # => 201
335
+ response = client.invoice_messages.create(invoice_id, data)
336
+ ```
337
+
338
+ ### [Expense Resource](https://www.fakturoid.cz/api/v3/expenses)
339
+
340
+ Get a list of expenses:
341
+
342
+ ```ruby
343
+ response = client.expenses.all
344
+ ```
345
+
346
+ Fulltext search:
347
+
348
+ ```ruby
349
+ response = client.expenses.search(query: "Supplier name")
350
+ response = client.expenses.search(tags: "Housing")
351
+ response = client.expenses.search(tags: ["Housing", "Rent"])
352
+ response = client.expenses.search(query: "Supplier name", tags: ["Housing"])
353
+ ```
354
+
355
+ Get expense details:
356
+
357
+ ```ruby
358
+ response = client.expenses.find(expense_id)
359
+ ```
360
+
361
+ Download an attachment:
362
+
363
+ ```ruby
364
+ response = client.expenses.download_attachment(expense_id, attachment_id)
365
+
366
+ File.open("/path/to/attachment.pdf", "wb") do |f|
367
+ f.write(response.body)
368
+ end
369
+ ```
370
+
371
+ Expense actions (eg. lock expense etc., full list is in the API documentation):
372
+
373
+ ```ruby
374
+ response = client.expenses.fire(expense_id, "lock")
375
+ ```
376
+
377
+ Create an expense:
378
+
379
+ ```ruby
380
+ data = {
381
+ subject_id: 123,
382
+ lines: [
383
+ {
384
+ quantity: 5,
385
+ unit_name: "kg",
386
+ name: "Sand",
387
+ unit_price: "100",
388
+ vat_rate: 21
389
+ }
390
+ ]
391
+ }
392
+ response = client.expenses.create(data)
393
+ ```
394
+
395
+ Update an expense:
396
+
397
+ ```ruby
398
+ response = client.expenses.update(expense_id, number: "N20240201")
194
399
  ```
195
400
 
196
- To update invoice use following code:
401
+ Delete an expense:
197
402
 
198
403
  ```ruby
199
- response = Fakturoid::Client::Invoice.update(invoice_id, number: "2015-0015")
404
+ response = client.expenses.delete(expense_id)
200
405
  ```
201
406
 
202
- Delete invoice:
407
+ ### [Expense Payment Resource](https://www.fakturoid.cz/api/v3/expense-payments)
408
+
409
+ Create an expense payment:
410
+
411
+ ```ruby
412
+ response = client.expense_payments.create(expense_id, paid_on: Date.today)
413
+ response = client.expense_payments.create(expense_id, amount: "500")
414
+ ````
415
+
416
+ Delete a payment:
203
417
 
204
418
  ```ruby
205
- response = Fakturoid::Client::Invoice.delete(invoice_id)
419
+ response = client.expense_payments.delete(expense_id, payment_id)
206
420
  ```
207
421
 
208
- For the list of all invoice fields and options see the [Invoices API documentation](https://fakturoid.docs.apiary.io/#reference/invoices)
422
+ ### [Inbox File Resource](https://www.fakturoid.cz/api/v3/inbox-files)
209
423
 
210
- ### InventoryItem resource
424
+ Get a list of inbox files:
211
425
 
212
- To get all inventory items:
426
+ ```ruby
427
+ response = client.inbox_files.all
428
+ ```
213
429
 
430
+ Create an inbox file:
431
+
214
432
  ```ruby
215
- response = Fakturoid::Client::InventoryItems.all
433
+ require "base64"
434
+
435
+ client.inbox_files.create(
436
+ attachment: "data:application/pdf;base64,#{Base64.urlsafe_encode64(File.read("some-file.pdf"))}",
437
+ filename: "some-file.pdf", # This is optional and defaults to `attachment.{extension}`.
438
+ send_to_ocr: true # Also optional
439
+ )
216
440
  ```
217
441
 
218
- To filter inventory items by certain SKU code:
442
+ Send a file to OCR (data extraction service):
219
443
 
220
444
  ```ruby
221
- response = Fakturoid::Client::InventoryItems.all(sku: 'SKU1234')
445
+ client.inbox_files.send_to_ocr(inbox_file_id)
222
446
  ```
223
447
 
224
- To search inventory items (searches in `name`, `article_number` and `sku`):
448
+ Download a file:
225
449
 
226
450
  ```ruby
227
- response = Fakturoid::Client::InventoryItems.search('Item name')
451
+ filename = client.inbox_files.find(inbox_file_id).filename
452
+ response = client.inbox_files.download(inbox_file_id)
453
+
454
+ File.open("/path/to/file.pdf", "wb") do |f|
455
+ f.write(response.body)
456
+ end
228
457
  ```
229
458
 
230
- To get all archived inventory items:
459
+ Delete a file:
231
460
 
232
461
  ```ruby
233
- response = Fakturoid::Client::InventoryItems.archived
462
+ response = client.inbox_files.delete(inbox_file_id)
234
463
  ```
235
464
 
236
- To get a single inventory item:
465
+ ### [InventoryItem Resource](https://www.fakturoid.cz/api/v3/inventory-items)
466
+
467
+ Get a list of inventory items:
237
468
 
238
469
  ```ruby
239
- response = Fakturoid::Client::InventoryItems.find(inventory_item_id)
470
+ response = client.inventory_items.all
471
+ response = client.inventory_items.all(sku: "SKU1234") # Filter by SKU code
240
472
  ```
241
473
 
242
- To create an inventory item:
474
+ Get a list of archived inventory items:
243
475
 
244
476
  ```ruby
245
- inventory_item = {
477
+ response = client.inventory_items.archived
478
+ ```
479
+
480
+ Get a list of inventory items that are running low on quantity:
481
+
482
+ ```ruby
483
+ response = client.inventory_items.low_quantity
484
+ ```
485
+
486
+ Search inventory items (searches in `name`, `article_number` and `sku`):
487
+
488
+ ```ruby
489
+ response = client.inventory_items.search(query: "Item name")
490
+ ```
491
+
492
+ Get a single inventory item:
493
+
494
+ ```ruby
495
+ response = client.inventory_items.find(inventory_item_id)
496
+ ```
497
+
498
+ Create an inventory item:
499
+
500
+ ```ruby
501
+ data = {
246
502
  name: "Item name",
247
503
  sku: "SKU1234",
248
504
  track_quantity: true,
@@ -250,57 +506,57 @@ inventory_item = {
250
506
  native_purchase_price: 500,
251
507
  native_retail_price: 1000
252
508
  }
253
- response = Fakturoid::Client::InventoryItems.create(inventory_item)
509
+ response = client.inventory_items.create(data)
254
510
  ```
255
511
 
256
- To update an inventory item:
512
+ Update an inventory item:
257
513
 
258
514
  ```ruby
259
- response = Fakturoid::Client::InventoryItems.update(inventory_item_id, name: "Another name")
515
+ response = client.inventory_items.update(inventory_item_id, name: "Another name")
260
516
  ```
261
517
 
262
- To archive an inventory item:
518
+ Delete an inventory item:
263
519
 
264
520
  ```ruby
265
- response = Fakturoid::Client::InventoryItems.archive(inventory_item_id)
521
+ response = client.inventory_items.delete(inventory_item_id)
266
522
  ```
267
523
 
268
- To unarchive an inventory item:
524
+ Archive an inventory item:
269
525
 
270
526
  ```ruby
271
- response = Fakturoid::Client::InventoryItems.unarchive(inventory_item_id)
527
+ response = client.inventory_items.archive(inventory_item_id)
272
528
  ```
273
529
 
274
- To delete an inventory item:
530
+ Unarchive an inventory item:
275
531
 
276
532
  ```ruby
277
- response = Fakturoid::Client::InventoryItems.delete(inventory_item_id)
533
+ response = client.inventory_items.unarchive(inventory_item_id)
278
534
  ```
279
535
 
280
- ### InventoryMove resource
536
+ ### [InventoryMove Resource](https://www.fakturoid.cz/api/v3/inventory-moves)
281
537
 
282
- To get get all inventory moves across all inventory items:
538
+ Get a list of inventory moves across all inventory items:
283
539
 
284
540
  ```ruby
285
- response = Fakturoid::Client::InventoryMoves.all
541
+ response = client.inventory_moves.all
286
542
  ```
287
543
 
288
- To get inventory moves for a single inventory item:
544
+ Get a list of inventory moves for a single inventory item:
289
545
 
290
546
  ```ruby
291
- response = Fakturoid::Client::InventoryMoves.all(inventory_item_id: inventory_item_id)
547
+ response = client.inventory_moves.all(inventory_item_id: inventory_item_id)
292
548
  ```
293
549
 
294
- To get a single inventory move:
550
+ Get a single inventory move:
295
551
 
296
552
  ```ruby
297
- response = Fakturoid::Client::InventoryMoves.find(inventory_item_id, inventory_move_id)
553
+ response = client.inventory_moves.find(inventory_item_id, inventory_move_id)
298
554
  ```
299
555
 
300
- To create a stock-in inventory move:
556
+ Create a stock-in inventory move:
301
557
 
302
558
  ```ruby
303
- response = Fakturoid::Client::InventoryMoves.create(
559
+ response = client.inventory_moves.create(
304
560
  inventory_item_id,
305
561
  direction: "in",
306
562
  moved_on: Date.today,
@@ -311,10 +567,10 @@ response = Fakturoid::Client::InventoryMoves.create(
311
567
  )
312
568
  ```
313
569
 
314
- To create a stock-out inventory move:
570
+ Create a stock-out inventory move:
315
571
 
316
572
  ```ruby
317
- response = Fakturoid::Client::InventoryMoves.create(
573
+ response = client.inventory_moves.create(
318
574
  inventory_item_id,
319
575
  direction: "out",
320
576
  moved_on: Date.today,
@@ -325,29 +581,181 @@ response = Fakturoid::Client::InventoryMoves.create(
325
581
  )
326
582
  ```
327
583
 
328
- To update an inventory move:
584
+ Update an inventory move:
329
585
 
330
586
  ```ruby
331
- inventory_move = {
587
+ data = {
332
588
  private_note: "Text"
333
589
  # Plus other fields if necessary
334
590
  }
335
- response = Fakturoid::Client::InventoryMoves.update(inventory_item_id, inventory_move_id, inventory_move)
591
+ response = client.inventory_moves.update(inventory_item_id, inventory_move_id, data)
592
+ ```
593
+
594
+ Delete an inventory move:
595
+
596
+ ```ruby
597
+ response = client.inventory_moves.delete(inventory_item_id, inventory_move_id)
598
+ ```
599
+
600
+ ### [Generator Resource](https://www.fakturoid.cz/api/v3/generators)
601
+
602
+ Get a list of generators:
603
+
604
+ ```ruby
605
+ response = client.generators.all
606
+ ```
607
+
608
+ Get generator details:
609
+
610
+ ```ruby
611
+ response = client.generators.find(generator_id)
612
+ ```
613
+
614
+ Create a generator:
615
+
616
+ ```ruby
617
+ data = {
618
+ name: "Workshop",
619
+ subject_id: 123,
620
+ lines: [
621
+ {
622
+ quantity: 5,
623
+ unit_name: "kg",
624
+ name: "Sand",
625
+ unit_price: "100",
626
+ vat_rate: 21
627
+ }
628
+ ]
629
+ }
630
+ response = client.generators.create(data)
631
+ ```
632
+
633
+ Update an generator:
634
+
635
+ ```ruby
636
+ response = client.generators.update(generator_id, name: "Another name")
637
+ ```
638
+
639
+ Delete an generator:
640
+
641
+ ```ruby
642
+ response = client.generators.delete(generator_id)
643
+ ```
644
+
645
+ ### [RecurringGenerator Resource](https://www.fakturoid.cz/api/v3/recurring-generators)
646
+
647
+ Get a list of recurring generators:
648
+
649
+ ```ruby
650
+ response = client.recurring_generators.all
651
+ ```
652
+
653
+ Get recurring generator details:
654
+
655
+ ```ruby
656
+ response = client.recurring_generators.find(recurring_generator_id)
657
+ ```
658
+
659
+ Create a recurring generator:
660
+
661
+ ```ruby
662
+ data = {
663
+ name: "Workshop",
664
+ subject_id: subject_id,
665
+ start_date: Date.today,
666
+ months_period: 1,
667
+ lines: [
668
+ {
669
+ quantity: 5,
670
+ unit_name: "kg",
671
+ name: "Sand",
672
+ unit_price: "100",
673
+ vat_rate: 21
674
+ }
675
+ ]
676
+ }
677
+ response = client.recurring_generators.create(data)
678
+ ```
679
+
680
+ Update a recurring generator:
681
+
682
+ ```ruby
683
+ response = client.recurring_generators.update(recurring_generator_id, name: "Another name")
684
+ ```
685
+
686
+ Delete a recurring generator:
687
+
688
+ ```ruby
689
+ response = client.recurring_generators.delete(recurring_generator_id)
690
+ ```
691
+ ### [Event Resource](https://www.fakturoid.cz/api/v3/events)
692
+
693
+ Get a list of all events:
694
+
695
+ ```ruby
696
+ response = client.events.all
697
+ ````
698
+
699
+ Get a list of document-paid events:
700
+
701
+ ```ruby
702
+ response = client.events.paid
703
+ ````
704
+
705
+ ### [Todo Resource](https://www.fakturoid.cz/api/v3/todos)
706
+
707
+ Get a list of all todos:
708
+
709
+ ```ruby
710
+ response = client.todos.all
711
+ ````
712
+
713
+ Toggle a todo completion:
714
+
715
+ ```ruby
716
+ response = client.todos.toggle_completion(todo_id)
717
+ ```
718
+
719
+ ### [Webhook Resource](https://www.fakturoid.cz/api/v3/webhooks)
720
+
721
+ Get a list of all webhooks:
722
+
723
+ ```ruby
724
+ response = client.webhooks.all
725
+ ```
726
+
727
+ Get a single webhook:
728
+
729
+ ```ruby
730
+ response = client.webhooks.find(webhook_id)
731
+ ```
732
+
733
+ Create a webhook:
734
+
735
+ ```ruby
736
+ response = client.webhooks.create(webhook_url: "https://example.com/webhook", events: %w[invoice_created])
737
+ ```
738
+
739
+ Update a webhook:
740
+
741
+ ```ruby
742
+ response = client.webhooks.update(webhook_id, webhook_url: "https://example.com/webhook")
336
743
  ```
337
744
 
338
- To delete an inventory move:
745
+ Delete a webhook:
339
746
 
340
747
  ```ruby
341
- response = Fakturoid::Client::InventoryMoves.delete(inventory_item_id, inventory_move_id)
748
+ response = client.webhooks.delete(webhook_id)
342
749
  ```
343
750
 
344
- ## Handling error responses
751
+ ## Handling Errors
345
752
 
346
- The Fakturoid gem raises exceptions if error response is returned from the servers. All exceptions contains following attributes:
753
+ The Fakturoid gem raises exceptions if server responds with an error.
754
+ All exceptions except `ConfigurationError` contain following attributes:
347
755
 
348
- - `message` - Error description
349
- - `response_code` - http code of error (only number)
350
- - `response_body` - response body parsed in the hash
756
+ - `message`: Error description
757
+ - `response_code`: HTTP code of error (only number)
758
+ - `response_body`: Response body parsed as a hash
351
759
 
352
760
  <table>
353
761
  <thead>
@@ -357,49 +765,36 @@ The Fakturoid gem raises exceptions if error response is returned from the serve
357
765
  </thead>
358
766
  <tbody>
359
767
  <tr>
360
- <td>ContentTypeError</td><td>415 Unsupported Media Type</td><td>Wrong content type</td>
361
- </tr>
362
- <tr>
363
- <td>UserAgentError</td><td>400 Bad Request</td><td>Missing `user_agent` configuration</td>
364
- </tr>
365
- <tr>
366
- <td>PaginationError</td><td>400 Bad Request</td><td>Page with given number does not exist</td>
367
- </tr>
368
- <tr>
369
- <td>AuthenticationError</td><td>401 Unauthorized</td><td>Wrong authentication `email` or `api_key` configuration</td>
370
- </tr>
371
- <tr>
372
- <td>BlockedAccountError</td><td>402 Payment Required</td><td>Fakturoid account is blocked</td>
768
+ <td>ConfigurationError</td><td>N/A</td><td>Important configuration is missing.</td>
373
769
  </tr>
374
770
  <tr>
375
- <td>RateLimitError</td><td>429 Too Many Requests</td><td>Too many request sent during last 5 minutes</td>
771
+ <td>OauthError</td><td>400 Bad Request</td><td>OAuth request fails.</td>
376
772
  </tr>
377
773
  <tr>
378
- <td>ReadOnlySiteError</td><td>503 Service Unavailable</td><td>Fakturoid is read only</td>
774
+ <td>AuthenticationError</td><td>401 Unauthorized</td><td>Authentication fails due to client credentials error or access token expired.</td>
379
775
  </tr>
380
776
  <tr>
381
- <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>
777
+ <td>ClientError</td><td>4XX</td><td>User-sent data are invalid.</td>
382
778
  </tr>
383
779
  <tr>
384
- <td>InvalidRecordError</td><td>422 Unprocessable Entity</td><td>Invalid data sent to server</td>
385
- </tr>
386
- <tr>
387
- <td>DestroySubjectError</td><td>403 Forbidden</td><td>Subject has invoices or expenses and cannot be deleted</td>
388
- </tr>
389
- <tr>
390
- <td>SubjectLimitError</td><td>403 Forbidden</td><td>Subject quota reached for adding more subjects upgrade to higher plan</td>
391
- </tr>
392
- <tr>
393
- <td>GeneratorLimitError</td><td>403 Forbidden</td><td>Generator quota reached for adding more recurring generators upgrade to higher plan</td>
394
- </tr>
395
- <tr>
396
- <td>UnsupportedFeatureError</td><td>403 Forbidden</td><td>Feature is not supported in your plan to use this feature upgrade to higher plan</td>
397
- </tr>
398
- <tr>
399
- <td>ClientError</td><td>4XX</td><td>Server returns response code which is not specified above</td>
400
- </tr>
401
- <tr>
402
- <td>ServerError</td><td>5XX</td><td>Server returns response code which is not specified above</td>
780
+ <td>ServerError</td><td>5XX</td><td>An exception happened while processing a request.</td>
403
781
  </tr>
404
782
  </tbody>
405
783
  </table>
784
+
785
+ ## Contributing
786
+
787
+ - Make a pull request with requested changes.
788
+ - Make sure the pull request is as small as possible. If you encounter something that should be changed but is unrelated,
789
+ please make a separate pull request for that.
790
+ - Do not change the version number inside the pull request – this will be done after it is merged.
791
+
792
+ ## Development
793
+
794
+ ```sh
795
+ git clone <repo-url>
796
+ cd fakturoid-ruby
797
+ bundle
798
+ bundle exec rake # Run tests
799
+ bundle exec rake build # Test the package building process
800
+ ```