fakturoid 0.4.0 → 1.0.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -11
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +15 -0
  5. data/README.md +597 -107
  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.rb +84 -9
  27. data/lib/fakturoid/client.rb +46 -10
  28. data/lib/fakturoid/config.rb +69 -12
  29. data/lib/fakturoid/oauth/access_token_service.rb +46 -0
  30. data/lib/fakturoid/oauth/credentials.rb +63 -0
  31. data/lib/fakturoid/oauth/flow/authorization_code.rb +53 -0
  32. data/lib/fakturoid/oauth/flow/base.rb +42 -0
  33. data/lib/fakturoid/oauth/flow/client_credentials.rb +27 -0
  34. data/lib/fakturoid/oauth/flow.rb +5 -0
  35. data/lib/fakturoid/oauth/request/api.rb +11 -0
  36. data/lib/fakturoid/oauth/request/base.rb +60 -0
  37. data/lib/fakturoid/oauth/request/oauth.rb +24 -0
  38. data/lib/fakturoid/oauth/request.rb +5 -0
  39. data/lib/fakturoid/oauth/token_response.rb +56 -0
  40. data/lib/fakturoid/oauth.rb +39 -0
  41. data/lib/fakturoid/response.rb +8 -20
  42. data/lib/fakturoid/utils.rb +27 -0
  43. data/lib/fakturoid/version.rb +1 -1
  44. data/lib/fakturoid.rb +22 -22
  45. metadata +48 -51
  46. data/.github/workflows/rubocop.yml +0 -20
  47. data/.github/workflows/tests.yml +0 -27
  48. data/.gitignore +0 -7
  49. data/Gemfile +0 -6
  50. data/lib/fakturoid/api/arguments.rb +0 -21
  51. data/lib/fakturoid/api/http_methods.rb +0 -23
  52. data/lib/fakturoid/client/account.rb +0 -11
  53. data/lib/fakturoid/client/bank_account.rb +0 -11
  54. data/lib/fakturoid/client/event.rb +0 -19
  55. data/lib/fakturoid/client/expense.rb +0 -49
  56. data/lib/fakturoid/client/generator.rb +0 -44
  57. data/lib/fakturoid/client/invoice.rb +0 -73
  58. data/lib/fakturoid/client/number_format.rb +0 -11
  59. data/lib/fakturoid/client/subject.rb +0 -41
  60. data/lib/fakturoid/client/todo.rb +0 -18
  61. data/lib/fakturoid/client/user.rb +0 -20
  62. data/lib/fakturoid/connection.rb +0 -30
  63. data/lib/fakturoid/request.rb +0 -31
  64. data/test/api_test.rb +0 -24
  65. data/test/config_test.rb +0 -40
  66. data/test/fixtures/blocked_account.json +0 -8
  67. data/test/fixtures/invoice.json +0 -81
  68. data/test/fixtures/invoice.pdf +0 -0
  69. data/test/fixtures/invoice_error.json +0 -7
  70. data/test/fixtures/subjects.json +0 -52
  71. data/test/request_test.rb +0 -20
  72. data/test/response_test.rb +0 -189
  73. 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:
36
57
 
37
- ### Account resource
58
+ ```ruby
59
+ client = Fakturoid.client
60
+
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.
87
131
 
88
- ### Subject resource
132
+ ## Usage
89
133
 
90
- To get all subjects run (Subjects are paginated by 20 per page):
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)`.
136
+
137
+ ### [User Resource](https://www.fakturoid.cz/api/v3/users)
138
+
139
+ Get current user information along with a list of accounts he/she has access to
140
+
141
+ ```ruby
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).
145
+ ```
146
+
147
+ Accessing content of returned body:
148
+
149
+ ```ruby
150
+ response.body["name"] # Return name of your company.
151
+ response.name # Alternative way of getting the name of your company.
152
+ ```
153
+
154
+ Get a list of all account users:
91
155
 
92
156
  ```ruby
93
- response = Fakturoid::Client::Subject.all(page: 2)
157
+ response = client.users.all
94
158
  ```
95
159
 
96
- Fulltext search subjects:
160
+ ### [Account Resource](https://www.fakturoid.cz/api/v3/account)
161
+
162
+ Get Fakturoid account information:
97
163
 
98
164
  ```ruby
99
- response = Fakturoid::Client::Subject.search("Client name")
165
+ response = client.account.current
100
166
  ```
101
167
 
102
- To find one subject use:
168
+ ### [Bank Account Resource](https://www.fakturoid.cz/api/v3/bank-accounts)
169
+
170
+ Get a list of bank accounts for current account:
103
171
 
104
172
  ```ruby
105
- response = Fakturoid::Client::Subject.find(subject_id)
173
+ response = client.bank_accounts.all
106
174
  ```
107
175
 
108
- You can create new subject with:
176
+ ### [Number Format Resource](https://www.fakturoid.cz/api/v3/number-formats)
177
+
178
+ Get a list of invoice number formats for current account:
109
179
 
110
180
  ```ruby
111
- response = Fakturoid::Client::Subject.create(name: "New client")
181
+ response = client.number_formats.invoices
112
182
  ```
113
183
 
114
- To update subject use following code:
184
+ ### [Subject Resource](https://www.fakturoid.cz/api/v3/subjects)
185
+
186
+ Get a list of subjects:
115
187
 
116
188
  ```ruby
117
- response = Fakturoid::Client::Subject.update(subject_id, name: "Updated client")
189
+ response = client.subjects.all(page: 2)
118
190
  ```
119
191
 
120
- Delete subject:
192
+ Fulltext search:
121
193
 
122
194
  ```ruby
123
- Fakturoid::Client::Subject.delete subject_id
195
+ response = client.subjects.search(query: "Client name")
124
196
  ```
125
197
 
126
- For the list of all subject fields and options see the [Subjects API documentation](https://fakturoid.docs.apiary.io/#reference/subjects)
198
+ Get a specific subject:
127
199
 
128
- ### Invoice resource
200
+ ```ruby
201
+ response = client.subjects.find(subject_id)
202
+ ```
129
203
 
130
- To get all invoices run (Invoices are paginated by 20 per page):
204
+ Create a new subject:
131
205
 
132
206
  ```ruby
133
- response = Fakturoid::Client::Invoice.all(page: 2)
207
+ response = client.subjects.create(name: "New client")
134
208
  ```
135
209
 
136
- Fulltext search invoices:
210
+ Update a subject:
137
211
 
138
212
  ```ruby
139
- response = Fakturoid::Client::Invoice.search("Client name")
213
+ response = client.subjects.update(subject_id, name: "Updated client")
140
214
  ```
141
215
 
142
- To find one invoice use:
216
+ Delete a subject:
143
217
 
144
218
  ```ruby
145
- response = Fakturoid::Client::Invoice.find(invoice_id)
219
+ client.subjects.delete(subject_id)
146
220
  ```
147
221
 
148
- To download invoice in PDF format you can use following code:
222
+ ### [Invoice Resource](https://www.fakturoid.cz/api/v3/invoices)
223
+
224
+ Get a list of invoices:
149
225
 
150
226
  ```ruby
151
- response = Fakturoid::Client::Invoice.download_pdf(invoice_id)
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):
266
+
267
+ ```ruby
268
+ response = client.invoices.fire(invoice_id, "lock")
269
+ ```
270
+
271
+ Create an invoice:
159
272
 
160
273
  ```ruby
161
- invoice = {
274
+ data = {
162
275
  subject_id: 123,
163
276
  lines: [
164
277
  {
@@ -170,50 +283,447 @@ 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:
296
+
297
+ ```ruby
298
+ response = client.invoices.delete(invoice_id)
299
+ ```
300
+
301
+ ### [Invoice Payment Resource](https://www.fakturoid.cz/api/v3/invoice-payments)
302
+
303
+ Create an invoice payment:
177
304
 
178
305
  ```ruby
179
- response = Fakturoid::Client::Invoice.fire(invoice_id, "pay")
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)
180
321
  ```
181
322
 
182
- Send invoice with customized message (for more information see [the API Documentation](https://fakturoid.docs.apiary.io/#reference/messages)):
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):
183
326
 
184
327
  ```ruby
185
- message = {
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)
194
336
  ```
195
337
 
196
- To update invoice use following code:
338
+ ### [Expense Resource](https://www.fakturoid.cz/api/v3/expenses)
339
+
340
+ Get a list of expenses:
197
341
 
198
342
  ```ruby
199
- response = Fakturoid::Client::Invoice.update(invoice_id, number: "2015-0015")
343
+ response = client.expenses.all
200
344
  ```
201
345
 
202
- Delete invoice:
346
+ Fulltext search:
203
347
 
204
348
  ```ruby
205
- response = Fakturoid::Client::Invoice.delete(invoice_id)
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"])
206
353
  ```
207
354
 
208
- For the list of all invoice fields and options see the [Invoices API documentation](https://fakturoid.docs.apiary.io/#reference/invoices)
355
+ Get expense details:
209
356
 
210
- ## Handling error responses
357
+ ```ruby
358
+ response = client.expenses.find(expense_id)
359
+ ```
211
360
 
212
- The Fakturoid gem raises exceptions if error response is returned from the servers. All exceptions contains following attributes:
361
+ Download an attachment:
213
362
 
214
- - `message` - Error description
215
- - `response_code` - http code of error (only number)
216
- - `response_body` - response body parsed in the hash
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")
399
+ ```
400
+
401
+ Delete an expense:
402
+
403
+ ```ruby
404
+ response = client.expenses.delete(expense_id)
405
+ ```
406
+
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:
417
+
418
+ ```ruby
419
+ response = client.expense_payments.delete(expense_id, payment_id)
420
+ ```
421
+
422
+ ### [Inbox File Resource](https://www.fakturoid.cz/api/v3/inbox-files)
423
+
424
+ Get a list of inbox files:
425
+
426
+ ```ruby
427
+ response = client.inbox_files.all
428
+ ```
429
+
430
+ Create an inbox file:
431
+
432
+ ```ruby
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
+ )
440
+ ```
441
+
442
+ Send a file to OCR (data extraction service):
443
+
444
+ ```ruby
445
+ client.inbox_files.send_to_ocr(inbox_file_id)
446
+ ```
447
+
448
+ Download a file:
449
+
450
+ ```ruby
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
457
+ ```
458
+
459
+ Delete a file:
460
+
461
+ ```ruby
462
+ response = client.inbox_files.delete(inbox_file_id)
463
+ ```
464
+
465
+ ### [InventoryItem Resource](https://www.fakturoid.cz/api/v3/inventory-items)
466
+
467
+ Get a list of inventory items:
468
+
469
+ ```ruby
470
+ response = client.inventory_items.all
471
+ response = client.inventory_items.all(sku: "SKU1234") # Filter by SKU code
472
+ ```
473
+
474
+ Get a list of archived inventory items:
475
+
476
+ ```ruby
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 = {
502
+ name: "Item name",
503
+ sku: "SKU1234",
504
+ track_quantity: true,
505
+ quantity: 100,
506
+ native_purchase_price: 500,
507
+ native_retail_price: 1000
508
+ }
509
+ response = client.inventory_items.create(data)
510
+ ```
511
+
512
+ Update an inventory item:
513
+
514
+ ```ruby
515
+ response = client.inventory_items.update(inventory_item_id, name: "Another name")
516
+ ```
517
+
518
+ Delete an inventory item:
519
+
520
+ ```ruby
521
+ response = client.inventory_items.delete(inventory_item_id)
522
+ ```
523
+
524
+ Archive an inventory item:
525
+
526
+ ```ruby
527
+ response = client.inventory_items.archive(inventory_item_id)
528
+ ```
529
+
530
+ Unarchive an inventory item:
531
+
532
+ ```ruby
533
+ response = client.inventory_items.unarchive(inventory_item_id)
534
+ ```
535
+
536
+ ### [InventoryMove Resource](https://www.fakturoid.cz/api/v3/inventory-moves)
537
+
538
+ Get a list of inventory moves across all inventory items:
539
+
540
+ ```ruby
541
+ response = client.inventory_moves.all
542
+ ```
543
+
544
+ Get a list of inventory moves for a single inventory item:
545
+
546
+ ```ruby
547
+ response = client.inventory_moves.all(inventory_item_id: inventory_item_id)
548
+ ```
549
+
550
+ Get a single inventory move:
551
+
552
+ ```ruby
553
+ response = client.inventory_moves.find(inventory_item_id, inventory_move_id)
554
+ ```
555
+
556
+ Create a stock-in inventory move:
557
+
558
+ ```ruby
559
+ response = client.inventory_moves.create(
560
+ inventory_item_id,
561
+ direction: "in",
562
+ moved_on: Date.today,
563
+ quantity_change: 5,
564
+ purchase_price: "249.99",
565
+ purchase_currency: "CZK",
566
+ private_note: "Bought with discount"
567
+ )
568
+ ```
569
+
570
+ Create a stock-out inventory move:
571
+
572
+ ```ruby
573
+ response = client.inventory_moves.create(
574
+ inventory_item_id,
575
+ direction: "out",
576
+ moved_on: Date.today,
577
+ quantity_change: "1.5",
578
+ retail_price: 50,
579
+ retail_currency: "EUR",
580
+ native_retail_price: "1250"
581
+ )
582
+ ```
583
+
584
+ Update an inventory move:
585
+
586
+ ```ruby
587
+ data = {
588
+ private_note: "Text"
589
+ # Plus other fields if necessary
590
+ }
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
+ ## Handling Errors
720
+
721
+ The Fakturoid gem raises exceptions if server responds with an error.
722
+ All exceptions except `ConfigurationError` contain following attributes:
723
+
724
+ - `message`: Error description
725
+ - `response_code`: HTTP code of error (only number)
726
+ - `response_body`: Response body parsed as a hash
217
727
 
218
728
  <table>
219
729
  <thead>
@@ -223,49 +733,29 @@ The Fakturoid gem raises exceptions if error response is returned from the serve
223
733
  </thead>
224
734
  <tbody>
225
735
  <tr>
226
- <td>ContentTypeError</td><td>415 Unsupported Media Type</td><td>Wrong content type</td>
227
- </tr>
228
- <tr>
229
- <td>UserAgentError</td><td>400 Bad Request</td><td>Missing `user_agent` configuration</td>
230
- </tr>
231
- <tr>
232
- <td>PaginationError</td><td>400 Bad Request</td><td>Page with given number does not exist</td>
233
- </tr>
234
- <tr>
235
- <td>AuthenticationError</td><td>401 Unauthorized</td><td>Wrong authentication `email` or `api_key` configuration</td>
236
- </tr>
237
- <tr>
238
- <td>BlockedAccountError</td><td>402 Payment Required</td><td>Fakturoid account is blocked</td>
239
- </tr>
240
- <tr>
241
- <td>RateLimitError</td><td>429 Too Many Requests</td><td>Too many request sent during last 5 minutes</td>
242
- </tr>
243
- <tr>
244
- <td>ReadOnlySiteError</td><td>503 Service Unavailable</td><td>Fakturoid is read only</td>
245
- </tr>
246
- <tr>
247
- <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>
248
- </tr>
249
- <tr>
250
- <td>InvalidRecordError</td><td>422 Unprocessable Entity</td><td>Invalid data sent to server</td>
251
- </tr>
252
- <tr>
253
- <td>DestroySubjectError</td><td>403 Forbidden</td><td>Subject has invoices or expenses and cannot be deleted</td>
736
+ <td>ConfigurationError</td><td>N/A</td><td>Important configuration is missing.</td>
254
737
  </tr>
255
738
  <tr>
256
- <td>SubjectLimitError</td><td>403 Forbidden</td><td>Subject quota reached for adding more subjects upgrade to higher plan</td>
739
+ <td>OauthError</td><td>400 Bad Request</td><td>OAuth request fails.</td>
257
740
  </tr>
258
741
  <tr>
259
- <td>GeneratorLimitError</td><td>403 Forbidden</td><td>Generator quota reached for adding more recurring generators upgrade to higher plan</td>
742
+ <td>AuthenticationError</td><td>401 Unauthorized</td><td>Authentication fails due to client credentials error or access token expired.</td>
260
743
  </tr>
261
744
  <tr>
262
- <td>UnsupportedFeatureError</td><td>403 Forbidden</td><td>Feature is not supported in your plan to use this feature upgrade to higher plan</td>
745
+ <td>ClientError</td><td>4XX</td><td>User-sent data are invalid.</td>
263
746
  </tr>
264
747
  <tr>
265
- <td>ClientError</td><td>4XX</td><td>Server returns response code which is not specified above</td>
266
- </tr>
267
- <tr>
268
- <td>ServerError</td><td>5XX</td><td>Server returns response code which is not specified above</td>
748
+ <td>ServerError</td><td>5XX</td><td>An exception happened while processing a request.</td>
269
749
  </tr>
270
750
  </tbody>
271
751
  </table>
752
+
753
+ ## Development
754
+
755
+ ```sh
756
+ git clone <repo-url>
757
+ cd fakturoid-ruby
758
+ bundle
759
+ bundle exec rake # Run tests
760
+ bundle exec rake build # Test the package building process
761
+ ```