eol-client 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 (77) hide show
  1. checksums.yaml +7 -0
  2. data/.drone.yaml +12 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +60 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +11 -0
  8. data/Changelog.md +3 -0
  9. data/Gemfile +6 -0
  10. data/Guardfile +13 -0
  11. data/LICENSE +21 -0
  12. data/README.md +247 -0
  13. data/Rakefile +13 -0
  14. data/bin/console +16 -0
  15. data/bin/setup +7 -0
  16. data/eol.gemspec +40 -0
  17. data/jenkins.sh +33 -0
  18. data/lib/eol.rb +79 -0
  19. data/lib/eol/api.rb +32 -0
  20. data/lib/eol/client.rb +13 -0
  21. data/lib/eol/config.rb +105 -0
  22. data/lib/eol/exception.rb +21 -0
  23. data/lib/eol/oauth.rb +117 -0
  24. data/lib/eol/parser.rb +42 -0
  25. data/lib/eol/request.rb +63 -0
  26. data/lib/eol/resource.rb +104 -0
  27. data/lib/eol/resources/account.rb +43 -0
  28. data/lib/eol/resources/address.rb +36 -0
  29. data/lib/eol/resources/aging_receivables_list.rb +34 -0
  30. data/lib/eol/resources/bank_account.rb +32 -0
  31. data/lib/eol/resources/bank_entry.rb +22 -0
  32. data/lib/eol/resources/bank_entry_line.rb +20 -0
  33. data/lib/eol/resources/base_entry_line.rb +20 -0
  34. data/lib/eol/resources/cash_entry.rb +22 -0
  35. data/lib/eol/resources/cash_entry_line.rb +20 -0
  36. data/lib/eol/resources/contact.rb +27 -0
  37. data/lib/eol/resources/costcenter.rb +19 -0
  38. data/lib/eol/resources/costunit.rb +19 -0
  39. data/lib/eol/resources/division.rb +26 -0
  40. data/lib/eol/resources/document.rb +23 -0
  41. data/lib/eol/resources/document_attachment.rb +19 -0
  42. data/lib/eol/resources/general_journal_entry.rb +19 -0
  43. data/lib/eol/resources/general_journal_entry_line.rb +11 -0
  44. data/lib/eol/resources/gl_account.rb +27 -0
  45. data/lib/eol/resources/goods_delivery.rb +37 -0
  46. data/lib/eol/resources/goods_delivery_line.rb +38 -0
  47. data/lib/eol/resources/item.rb +36 -0
  48. data/lib/eol/resources/item_group.rb +23 -0
  49. data/lib/eol/resources/journal.rb +23 -0
  50. data/lib/eol/resources/layout.rb +26 -0
  51. data/lib/eol/resources/mailbox.rb +22 -0
  52. data/lib/eol/resources/payment_condition.rb +25 -0
  53. data/lib/eol/resources/printed_sales_invoice.rb +37 -0
  54. data/lib/eol/resources/project.rb +26 -0
  55. data/lib/eol/resources/purchase_entry.rb +20 -0
  56. data/lib/eol/resources/purchase_entry_line.rb +11 -0
  57. data/lib/eol/resources/receivables_list.rb +31 -0
  58. data/lib/eol/resources/sales_entry.rb +22 -0
  59. data/lib/eol/resources/sales_entry_line.rb +12 -0
  60. data/lib/eol/resources/sales_invoice.rb +25 -0
  61. data/lib/eol/resources/sales_invoice_line.rb +24 -0
  62. data/lib/eol/resources/sales_item_prices.rb +18 -0
  63. data/lib/eol/resources/sales_order.rb +23 -0
  64. data/lib/eol/resources/sales_order_line.rb +23 -0
  65. data/lib/eol/resources/shared_sales_attributes.rb +11 -0
  66. data/lib/eol/resources/time_transaction.rb +24 -0
  67. data/lib/eol/resources/transaction.rb +23 -0
  68. data/lib/eol/resources/transaction_line.rb +23 -0
  69. data/lib/eol/resources/user.rb +27 -0
  70. data/lib/eol/resources/vat_code.rb +20 -0
  71. data/lib/eol/response.rb +72 -0
  72. data/lib/eol/result_set.rb +62 -0
  73. data/lib/eol/sanitizer.rb +54 -0
  74. data/lib/eol/uri.rb +87 -0
  75. data/lib/eol/utils.rb +50 -0
  76. data/lib/eol/version.rb +15 -0
  77. metadata +356 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a9ca2c43af778808a2e4726db835f1f4f696473a100ffc3bb7b980e568df4cbd
4
+ data.tar.gz: 8ddacb7b932ff7162ef6e7a24ad14dde73e60d02944ccbcf0b6c932edfaede0b
5
+ SHA512:
6
+ metadata.gz: ea4d653b89271be4b224912da05d3481e284db13707199ff1a571af10501d165dfff85fe26581672024774150b9ed29aecca15d4033e6f0149c6fdb690ee6366
7
+ data.tar.gz: 706b7cbb0c64759e603565ef89b82c307498f2dad72161eaa1b3935cb938620a4d66b825de7341e66c3ef866404d7b70134d7d0414ce45e7c272cf297c63b6de
data/.drone.yaml ADDED
@@ -0,0 +1,12 @@
1
+ cache:
2
+ mount:
3
+ - bundler
4
+ build:
5
+ image: ruby:2.2.3
6
+ cache:
7
+ - bundler
8
+ commands:
9
+ - apt-get update -qq
10
+ - apt-get install -y -qq build-essential &>/dev/null
11
+ - bundle install --jobs $(nproc) --path bundler
12
+ - ./script/ci
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .DS_Store
11
+ .env
12
+ .log
13
+ *.gem
14
+ *.swp
15
+ .idea
16
+ *.iml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,60 @@
1
+ Documentation:
2
+ Enabled: false
3
+
4
+ Lint/UriEscapeUnescape:
5
+ Enabled: false
6
+
7
+ NAming/FileName:
8
+ Enabled: false
9
+
10
+ Style/MethodMissing:
11
+ Enabled: false
12
+
13
+ StringLiterals:
14
+ EnforcedStyle: double_quotes
15
+
16
+ AllCops:
17
+ Include:
18
+ - '**/Rakefile'
19
+ - '**/config.ru'
20
+ Exclude:
21
+ - 'db/**/*'
22
+ - 'tmp/**/*'
23
+ - 'vendor/**/*'
24
+ - 'bin/**/*'
25
+ - 'log/**/*'
26
+ - 'spec/**/*'
27
+ - 'config/**/*'
28
+
29
+ Metrics/AbcSize:
30
+ Max: 30
31
+ Metrics/BlockNesting:
32
+ Max: 3
33
+ Metrics/ClassLength:
34
+ CountComments: false # count full line comments?
35
+ Max: 100
36
+ Metrics/CyclomaticComplexity:
37
+ Max: 6
38
+ Metrics/LineLength:
39
+ Max: 150
40
+ AllowURI: true
41
+ URISchemes:
42
+ - http
43
+ - https
44
+
45
+ Metrics/MethodLength:
46
+ CountComments: false # count full line comments?
47
+ Max: 13
48
+
49
+ Metrics/ParameterLists:
50
+ Max: 5
51
+ CountKeywordArgs: true
52
+
53
+ Metrics/PerceivedComplexity:
54
+ Max: 7
55
+ Style/PerlBackrefs:
56
+ Enabled: false
57
+ Lint/AmbiguousOperator:
58
+ Enabled: false
59
+ Rails/Delegate:
60
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.1
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5.1
4
+ cache: bundler
5
+ notifications:
6
+ webhooks:
7
+ urls:
8
+ - https://webhooks.gitter.im/e/fe18055a45cdf1a5ecae
9
+ on_success: change
10
+ on_failure: always
11
+ on_start: never
data/Changelog.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 1.0.0
2
+
3
+ - First release
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in eol.gemspec
6
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :rspec, cmd: "rspec" do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
6
+ watch("spec/spec_helper.rb") { "spec" }
7
+ end
8
+
9
+ guard :rubocop, all_on_start: false, cli: ["--format", "clang", "--rails"] do
10
+ watch(%r{^spec/.+_spec\.rb$})
11
+ watch(%r{^lib/(.+)\.rb$})
12
+ watch("spec/spec_helper.rb")
13
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) [2018] [Hoppinger]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,247 @@
1
+ # Eol
2
+
3
+ Eol stand for ExactOnline, it's just an API wrapper for [Exact Online](https://developers.exactonline.com/).
4
+
5
+ # DISCLAIMER
6
+
7
+ __As of 25th of May, 2FA will be mandatory for all Exact Online accounts. Therefor the auto authorize method with which you could simulate an App 2 App connection will not work anymore. Hoppinger is working on a new solution. The methods will stay available but probably won't work and will show a deprecation warning. [Read more about it here](https://support.exactonline.com/community/s/knowledge-base#All-All-HNO-Concept-general-security-gen-auth-totpc)__
8
+
9
+ ### Contributors
10
+
11
+ * [Ahmad](https://github.com/ahmadhasankhan)
12
+
13
+ Thanks for helping! If you want to contribute read through this readme how to!
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'eol-client'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install Eol
30
+
31
+ ## Authorization and Setup
32
+
33
+ You have to have an Exact Online account and an app setup to connect with.
34
+
35
+ You have to set a few variables to make a connection possible. I'd suggest using environment variables set with [dotenv](https://github.com/bkeepers/dotenv) for that.
36
+
37
+ Then configure Eol like this (take these values from your app that you setup at apps.exactonline.com)
38
+
39
+ ```ruby
40
+ Eol.configure do |config|
41
+ config.client_id = ENV['CLIENT_ID']
42
+ config.client_secret = ENV['CLIENT_SECRET']
43
+ config.redirect_uri = ENV['REDIRECT_URI']
44
+ end
45
+ ```
46
+
47
+ You then have to retrieve an access token for the user you want to login with. You can setup a user facing OAUTH2 flow or set the `access_token` and/or refresh token on the go.
48
+
49
+ ```ruby
50
+ Eol.configure do |config|
51
+ config.access_token = "42"
52
+ config.refresh_token = "42"
53
+ end
54
+ ```
55
+
56
+ Once you've set your access tokens you should be able to do requests. You'll need a division number, you can retrieve that with the following line of code:
57
+
58
+ ```
59
+ get("/Current/Me", no_division: true).results.first.current_division
60
+ ```
61
+
62
+
63
+ ### Logger
64
+
65
+ The default logger is STDOUT. A custom logger can be be configured.
66
+
67
+ ```ruby
68
+ dir = File.dirname("./tmp/errors.log")
69
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
70
+
71
+ Eol.configure do |config|
72
+ config.logger = ::Logger.new("./tmp/errors.log", "daily")
73
+ end
74
+ ```
75
+
76
+ ## Accessing the API
77
+
78
+ We can retrieve data from the API using the following syntax.
79
+
80
+ The query will return an `Eol::ResultSet` which contains up to 60 records and
81
+ a method to retrieve the next page of results. Unfortunately the ExactOnline API
82
+ does not allow us to retrieve a specific page or define how many records we want
83
+ to retrieve at a time.
84
+
85
+ ```ruby
86
+ # Query the API and return an Eol::ResultSet
87
+ accounts = Eol::Account.new.find_all
88
+
89
+ # Return an array of accounts
90
+ accounts.records
91
+ ```
92
+
93
+ If the query results in more than 60 records the next set can be retrieved using
94
+ the `next_page` method.
95
+
96
+ ```ruby
97
+ # Return an Eol::ResultSet containing the next page's records
98
+ accounts.next_page
99
+ ```
100
+
101
+ ### Filter and sort results
102
+
103
+ Filtering result sets can be done by adding attributes to the initializer and then
104
+ using `find_by`. Filters accept a single value or an array of values.
105
+
106
+ ```ruby
107
+ # Find the account with code 123
108
+ accounts = Eol::Account.new(code: '123').find_by(filters: [:code])
109
+
110
+ # Find the accounts with code 123 and 345
111
+ accounts = Eol::Account.new(code: ['123', '345']).find_by(filters: [:code])
112
+ ```
113
+
114
+ You can also match on values "greater than" or "less than" by specifying `gt` or `lt`:
115
+
116
+ ```ruby
117
+ # Find all AgingReceivables with an amount greater than 0 in the third age range
118
+ Eol::AgingReceivablesList.new(age_group3_amount: { gt: 0 }).find_by(filters: [:age_group3_amount])
119
+ ```
120
+
121
+ Results can be sorted in the same way
122
+
123
+ ```ruby
124
+ # Return all accounts sorted by first name
125
+ accounts = Eol::Account.new.find_all(order_by: :first_name)
126
+ ```
127
+
128
+ Filters and sorting can also be combined
129
+
130
+ ```ruby
131
+ # Return accounts with code 123 and 345 sorted by first name
132
+ accounts = Eol::Account.new(code: ['123', '345']).find_by(filters: [:code], order_by: :first_name)
133
+ ```
134
+
135
+ To find an individual record by its ID the `find` method can be used
136
+
137
+ ```ruby
138
+ # Return the account with guid
139
+ account = Eol::Account.new(id: '9e3a078e-55dc-40f4-a490-1875400a3e10').find
140
+ ```
141
+
142
+ For more information on this way of selecting data look here http://www.odata.org/
143
+
144
+ ### Creating new records
145
+
146
+ Use the initializer method followed by 'save' to create a new record:
147
+
148
+ ```ruby
149
+ # Create a new contact
150
+ contact = Eol::Contact.new(first_name: "Karel", last_name: "Appel", account: "8d87c8c5-f1c6-495c-b6af-d5ba396873b5" )
151
+ contact.save
152
+ ```
153
+
154
+ ### Projects and Time Tracking
155
+
156
+ Project Types:
157
+
158
+ - :type=>2, :type_description=>"Fixed price"
159
+ - :type=>3, :type_description=>"Time and Material"
160
+ - :type=>4, :type_description=>"Non billable"
161
+ - :type=>5, :type_description=>"Prepaid"
162
+
163
+ To create a new project
164
+
165
+ ```ruby
166
+ project = Eol::Project.new(code: "PROJ902343", description: "Great project", account: "8d87c8c5-f1c6-495c-b6af-d5ba396873b5", type: 2 )
167
+ project.save
168
+ ```
169
+
170
+ To submit a new time transaction
171
+
172
+ ```ruby
173
+ hours = Eol::TimeTransaction.new(account: "8d87c8c5-f1c6-495c-b6af-d5ba396873b5", item: "eb73942a-53c0-4ee9-bbb2-6d985814a1b1", quantity: 3.0, notes: "")
174
+ hours.save
175
+ ```
176
+
177
+ ### SalesInvoice flow
178
+ SalesInvoices have a relationship with SalesInvoiceLines. A SalesInvoice has many
179
+ SalesInvoiceLines and a SalesInvoiceLine belongs to a SalesInvoice. To create a
180
+ valid SalesInvoice you need to embed the SalesInvoiceLines
181
+
182
+ ```ruby
183
+ sales_invoice = Eol::SalesInvoice.new(journal: "id of your journal", ordered_by: "id of customer")
184
+ ```
185
+ Now it still needs SalesInvoiceLines
186
+
187
+ ```ruby
188
+ sales_invoice_lines = []
189
+ sales_invoice_lines << Eol::SalesInvoiceLine.new(item: "id of item being sold") # do this for each item you want in the invoice.
190
+ sales_invoice.sales_invoice_lines = sales_invoice_lines
191
+ ```
192
+ Now you can save the SalesInvoice and it will be parsed to the following
193
+ ```ruby
194
+ sales_invoice.save
195
+ # Sanitized object: {"Journal"=>"id of your journal", "OrderedBy"=>"id of customer", "SalesInvoiceLines"=>[{"Item"=>"id of item being sold"}]}
196
+ ```
197
+
198
+ If you have a SalesInvoice with an id(so saved before already), you can also create invoice lines without embedding
199
+
200
+ ```ruby
201
+ sales_invoice = Eol::SalesInvoice.new({id: "1"}).first
202
+ sales_invoice_line = Eol::SalesInvoiceLine.new(invoice_ID: sales_invoice, item: "42")
203
+ sales_invoice.save
204
+ # Sanitized object: {"Item"=>"42", "InvoiceID"=>"1"}
205
+ ```
206
+
207
+ For many resources there are mandatory attributes, you can see that in the classes
208
+ for every resource. For example for Contact: https://github.com/exactonline/exactonline-api-ruby-client/blob/master/lib/Eol/resources/contact.rb
209
+
210
+ ###Divisions and Endpoints
211
+
212
+ Usually in the exact wrapper you need a division number, this one will be set on authorization checks (with `/Current/Me` endpoint). Sometimes you need to do a request without the division number, or even without the standard `/api/v1` endpoint. Like so:
213
+
214
+ ```ruby
215
+ response = Eol.get('/api/oauth2/token', no_endpoint: true, no_division: true)
216
+ response = Eol.get('/Current/Me', no_division: true)
217
+ ```
218
+
219
+ ## Development
220
+
221
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
222
+
223
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
224
+
225
+ ## Contributing
226
+
227
+ 1. Fork it ( https://github.com/[my-github-username]/eol/fork )
228
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
229
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
230
+ 4. Push to the branch (`git push origin my-new-feature`)
231
+ 5. Create a new Pull Request
232
+
233
+ ## Testing
234
+
235
+ We use Rspec for normal unit testing. We aim for coverage above 90%. Also the current suite should succeed when you commit something.
236
+ We use Rubocop for style checking, this should also succeed before you commit anything.
237
+
238
+ We're also experimenting with Mutation testing, which alters your code to test if your specs fail when there's faulty code. This is important when you
239
+ alter a vital part of the code, make sure the mutation percentage is higher than 80%. To run a part of the code with mutant run the follwing
240
+ `mutant --include lib/Eol --require Eol --use rspec Eol::ClassYoureWorkingOn`
241
+
242
+ To test the vital classes run this
243
+ `mutant --include lib --require Eol --use rspec Eol::Response Eol::Client Eol::Utils Eol::Resource Eol::Request Eol::Parser Eol::Config`
244
+ This will take a few minutes
245
+
246
+ When you're editing code it's advised you run guard, which watches file changes and automatically runs Rspec and Rubocop.
247
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ task :rspec do
6
+ sh "rspec"
7
+ end
8
+
9
+ task :rubocop do
10
+ sh "rubocop"
11
+ end
12
+
13
+ task default: %i[rspec]
data/bin/console ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "eol"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ require "dotenv"
15
+ Dotenv.load
16
+ IRB.start