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
data/lib/eol/parser.rb ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ class Parser
5
+ attr_accessor :parsed_json
6
+
7
+ def initialize(json)
8
+ @parsed_json = JSON.parse(json)
9
+ rescue JSON::ParserError => e
10
+ Eol.error "There was an error parsing the response"
11
+ Eol.error "#{e.class}: #{e.message}"
12
+ @parsed_json = ""
13
+ @error_message = ""
14
+ end
15
+
16
+ def results
17
+ result["results"] if result && result["results"]
18
+ end
19
+
20
+ def metadata
21
+ result["__metadata"] if result && result["__metadata"]
22
+ end
23
+
24
+ def result
25
+ parsed_json["d"]
26
+ end
27
+
28
+ def next_page_url
29
+ result && result["__next"]
30
+ end
31
+
32
+ def error_message
33
+ @error_message ||= begin
34
+ parsed_json["error"]["message"]["value"] if parsed_json["error"]
35
+ end
36
+ end
37
+
38
+ def first_result
39
+ results[0]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ # Defines HTTP request methods
5
+ module Request
6
+ # Perform an HTTP GET request
7
+ def get(path, options = {})
8
+ request(:get, path, options)
9
+ end
10
+
11
+ # Perform an HTTP POST request
12
+ def post(path, options = {})
13
+ request(:post, path, options)
14
+ end
15
+
16
+ # Perform an HTTP PUT request
17
+ def put(path, options = {})
18
+ request(:put, path, options)
19
+ end
20
+
21
+ # Perform an HTTP DELETE request
22
+ def delete(path, options = {})
23
+ request(:delete, path, options)
24
+ end
25
+
26
+ private
27
+
28
+ def build_path(path, options)
29
+ unless options[:use_raw_path]
30
+ path = "#{division}/#{path}" unless options[:no_division]
31
+ path = "#{endpoint}/#{path}" unless options[:no_endpoint]
32
+ path = "#{options[:url] || base_url}/#{path}"
33
+ end
34
+ path
35
+ end
36
+
37
+ def add_headers(options = {})
38
+ content_type = options[:content_type] || "application/#{response_format}"
39
+ headers = {}
40
+ headers["Content-Type"] = content_type
41
+ headers["Accept"] = content_type
42
+ headers["Authorization"] = "Bearer #{access_token}" if access_token
43
+ headers
44
+ end
45
+
46
+ # Perform an HTTP request
47
+ def request(method, path, options = {})
48
+ path = build_path(path, options)
49
+
50
+ response = connection.send(method) do |request|
51
+ case method
52
+ when :post, :put
53
+ request.url path
54
+ request.body = options[:body] || options[:params].to_json
55
+ when :get, :delete
56
+ request.url path
57
+ end
58
+ request.headers = add_headers(options)
59
+ end
60
+ Response.new(response)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("../utils", __FILE__)
4
+ require File.expand_path("../exception", __FILE__)
5
+ require File.expand_path("../uri", __FILE__)
6
+ require File.expand_path("../sanitizer", __FILE__)
7
+
8
+ module Eol
9
+ module Resource
10
+ include UriMethods
11
+ include Sanitizer
12
+
13
+ attr_accessor :attributes, :url
14
+ attr_reader :response
15
+
16
+ def initialize(attributes = {})
17
+ @attributes = Utils.normalize_hash(attributes)
18
+ @filters = []
19
+ @query = []
20
+ end
21
+
22
+ def id
23
+ @attributes[:id]
24
+ end
25
+
26
+ def find_all(options = {})
27
+ @order_by = options[:order_by]
28
+ @select = options[:select]
29
+ response = get(uri(%i[order select]))
30
+ response&.results
31
+ end
32
+
33
+ # Pass filters in an array, for example 'filters: [:id, :name]'
34
+ def find_by(options = {})
35
+ @filters = options[:filters]
36
+ @order_by = options[:order_by]
37
+ @select = options[:select]
38
+ response = get(uri(%i[order select filters]))
39
+ response&.results
40
+ end
41
+
42
+ def find
43
+ return nil unless id?
44
+ response = get(uri([:id]))
45
+ response&.results&.first
46
+ end
47
+
48
+ # Normally use the url method (which applies the filters) but sometimes you only want to use the base path or other paths
49
+ def get(uri = self.uri)
50
+ @response = Eol.get(URI.unescape(uri.to_s))
51
+ end
52
+
53
+ def valid?
54
+ mandatory_attributes.all? do |attribute|
55
+ @attributes.key? attribute
56
+ end
57
+ end
58
+
59
+ def id?
60
+ !@attributes[:id].nil?
61
+ end
62
+
63
+ def save
64
+ attributes_to_submit = sanitize
65
+ if valid?
66
+ return @response = Eol.post(base_path, params: attributes_to_submit) unless id?
67
+ return @response = Eol.put(basic_identifier_uri, params: attributes_to_submit)
68
+ else
69
+ Eol.error("Invalid Resource #{self.class.name}, attributes: #{@attributes.inspect}")
70
+ Eol::Response.new(Faraday::Response.new(status: 400, body: "Invalid Request"))
71
+ end
72
+ end
73
+
74
+ def delete
75
+ return nil unless id?
76
+ Eol.delete(basic_identifier_uri)
77
+ end
78
+
79
+ # Getter/Setter for resource
80
+ def method_missing(method, *args, &block)
81
+ yield if block
82
+ if /^(\w+)=$/ =~ method
83
+ set_attribute($1, args[0])
84
+ else
85
+ nil unless @attributes[method.to_sym]
86
+ end
87
+ @attributes[method.to_sym]
88
+ end
89
+
90
+ private
91
+
92
+ def set_attribute(attribute, value)
93
+ @attributes[attribute.to_sym] = value if valid_attribute?(attribute)
94
+ end
95
+
96
+ def valid_attribute?(attribute)
97
+ valid_attributes.include?(attribute.to_sym)
98
+ end
99
+
100
+ def valid_attributes
101
+ @valid_attributes ||= mandatory_attributes.inject(other_attributes, :<<)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ class Account
5
+ # An account needs a name
6
+ include Eol::Resource
7
+
8
+ def base_path
9
+ "crm/Accounts"
10
+ end
11
+
12
+ def mandatory_attributes
13
+ %i[name]
14
+ end
15
+
16
+ # https//start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?name=CRMAccounts
17
+ # rubocop:disable Metrics/MethodLength
18
+ def other_attributes
19
+ %i[
20
+ accountant account_manager activity_sector
21
+ activity_sub_sector address_line1 address_line2
22
+ address_line3 blocked business_type can_drop_ship
23
+ chamber_of_commerce city code code_at_supplier
24
+ company_size consolidation_scenario controlled_date
25
+ cost_paid country credit_line_purchase credit_line_sales
26
+ discount_purchase discount_sales email end_date fax
27
+ intra_stat_area intra_stat_delivery_term intra_stat_system
28
+ intra_stat_transaction_a intra_stat_transaction_b
29
+ intra_stat_transport_method invoice_acount invoice_attachment_type
30
+ invoicing_method is_accountant is_agency is_competitor is_mailing
31
+ is_pilot is_reseller is_sales is_supplier language latitude
32
+ lead_source logo logo_file_name longitude main_contact
33
+ payment_condition_purchase payment_condition_sales phone
34
+ phone_extension postcode price_list purchase_currency
35
+ purchase_lead_days purchase_VAT_code recipient_of_commissions
36
+ remarks reseller sales_currency sales_tax_schedule sales_VAT_code
37
+ search_code security_level seperate_inv_per_project seperate_inv_per_subscription
38
+ shipping_lead_days shipping_method start_date state status
39
+ VAT_liability VAT_number website
40
+ ]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,36 @@
1
+ module Eol
2
+ class Address
3
+ # An account needs a name
4
+ include Eol::Resource
5
+
6
+ def base_path
7
+ "crm/Addresses"
8
+ end
9
+
10
+ def mandatory_attributes
11
+ [:type]
12
+ end
13
+
14
+ # https://start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?name=CRMAddresses
15
+ def other_attributes # rubocop:disable Metrics/MethodLength
16
+ [
17
+ :account, :account_is_supplier, :account_name,
18
+ :address_line1, :address_line2, :address_line3,
19
+ :city, :contact, :contact_name,
20
+ :country, :country_name, :created,
21
+ :creator, :creator_full_name, :division,
22
+ :fax, :free_bool_field_01, :free_bool_field_02,
23
+ :free_bool_field_03, :free_bool_field_04, :free_bool_field_05,
24
+ :free_date_field_01, :free_date_field_02, :free_date_field_03,
25
+ :free_date_field_04, :free_date_field_05, :free_number_field_01,
26
+ :free_number_field_02, :free_number_field_03, :free_number_field_04,
27
+ :free_number_field_05, :free_text_field_01, :free_text_field_02,
28
+ :free_text_field_03, :free_text_field_04, :free_text_field_05,
29
+ :mailbox, :main, :modified, :modifier, :modifier_full_name,
30
+ :nic_number, :notes, :phone, :phone_extension, :postcode,
31
+ :state, :state_description, :type,
32
+ :warehouse, :warehouse_code, :warehouse_description
33
+ ]
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ # We can use the AgingReceivablesList to change the status of SalesInvoices from
5
+ # Open to 'Verwerkt' while at the same time sending a PDF of the invoice to the
6
+ # end user by e-mail.
7
+ #
8
+ # This endpoint only supports the POST method.
9
+ #
10
+ class AgingReceivablesList
11
+ include Eol::Resource
12
+
13
+ def valid_actions
14
+ %i[get]
15
+ end
16
+
17
+ def base_path
18
+ "read/financial/AgingReceivablesList"
19
+ end
20
+
21
+ def mandatory_attributes
22
+ []
23
+ end
24
+
25
+ # https//start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?name=SalesInvoiceAgingReceivablesLists
26
+ def other_attributes
27
+ %i[
28
+ account_id account_code account_name age_group1 age_group1_amount age_group1_description
29
+ age_group2 age_group2_amount age_group2_description age_group3 age_group3_amount age_group3_description
30
+ age_group4 age_group4_amount age_group4_description currency_code total_amount
31
+ ]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ class BankAccount
5
+ # An account needs a name
6
+ include Eol::Resource
7
+
8
+ def valid_actions
9
+ %i[get]
10
+ end
11
+
12
+ def base_path
13
+ "crm/BankAccounts"
14
+ end
15
+
16
+ def mandatory_attributes
17
+ %i[account]
18
+ end
19
+
20
+ # https//start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?name=CRMAccounts
21
+ # rubocopdisable Metrics/MethodLength
22
+ def other_attributes
23
+ %i[
24
+ id account account_name bank
25
+ bank_account bank_description
26
+ bank_account_holder_name BIC_code
27
+ description division format IBAN
28
+ type type_description main
29
+ ]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ class BankEntry
5
+ include Eol::Resource
6
+
7
+ def base_path
8
+ "financialtransaction/BankEntries"
9
+ end
10
+
11
+ def mandatory_attributes
12
+ %i[journal_code bank_entry_lines]
13
+ end
14
+
15
+ def other_attributes
16
+ %i[
17
+ currency bank_statement_document closing_balance_FC entry_number
18
+ financial_period financial_year opening_balance_FC
19
+ ]
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ class BankEntryLine < Eol::BaseEntryLine
5
+ # A sales entry line belongs to a sales entry
6
+ include Eol::Resource
7
+
8
+ def base_path
9
+ "financialtransaction/BankEntryLines"
10
+ end
11
+
12
+ def other_attributes
13
+ %i[
14
+ account amount_VATFC asset cost_center cost_unit date
15
+ description notes document exchange_rate our_ref
16
+ project quantity VAT_code VAT_percentage VAT_type
17
+ ]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ class BaseEntryLine
5
+ include Eol::Resource
6
+
7
+ def mandatory_attributes
8
+ %i[amount_FC GL_account entry_ID]
9
+ end
10
+
11
+ def other_attributes
12
+ %i[
13
+ serial_number asset cost_center cost_unit description notes
14
+ project quantity serial_number subscription tracking_number
15
+ VAT_amount_FC VAT_base_amount_DC VAT_base_amount_FC VAT_code
16
+ VAT_percentage account date
17
+ ]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eol
4
+ class CashEntry
5
+ include Eol::Resource
6
+
7
+ def base_path
8
+ "financialtransaction/CashEntries"
9
+ end
10
+
11
+ def mandatory_attributes
12
+ %i[journal_code cash_entry_lines]
13
+ end
14
+
15
+ def other_attributes
16
+ %i[
17
+ currency closing_balance_FC entry_number
18
+ financial_period financial_year openening_balance_FC
19
+ ]
20
+ end
21
+ end
22
+ end