business-central 1.0.1 → 1.0.6

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +58 -15
  3. data/lib/business_central.rb +47 -2
  4. data/lib/business_central/client.rb +82 -39
  5. data/lib/business_central/exceptions.rb +30 -10
  6. data/lib/business_central/object/account.rb +4 -12
  7. data/lib/business_central/object/aged_account_payable.rb +4 -12
  8. data/lib/business_central/object/aged_account_receivable.rb +4 -12
  9. data/lib/business_central/object/argument_helper.rb +22 -0
  10. data/lib/business_central/object/attachment.rb +30 -0
  11. data/lib/business_central/object/balance_sheet.rb +4 -12
  12. data/lib/business_central/object/base.rb +100 -49
  13. data/lib/business_central/object/cash_flow_statement.rb +4 -12
  14. data/lib/business_central/object/company.rb +9 -2
  15. data/lib/business_central/object/company_information.rb +7 -15
  16. data/lib/business_central/object/country_region.rb +26 -0
  17. data/lib/business_central/object/currency.rb +29 -0
  18. data/lib/business_central/object/customer.rb +34 -0
  19. data/lib/business_central/object/customer_financial_detail.rb +13 -0
  20. data/lib/business_central/object/customer_payment.rb +43 -0
  21. data/lib/business_central/object/customer_payment_journal.rb +25 -0
  22. data/lib/business_central/object/customer_sale.rb +13 -0
  23. data/lib/business_central/object/default_dimension.rb +51 -0
  24. data/lib/business_central/object/dimension.rb +20 -0
  25. data/lib/business_central/object/dimension_line.rb +37 -0
  26. data/lib/business_central/object/dimension_value.rb +28 -0
  27. data/lib/business_central/object/employee.rb +21 -0
  28. data/lib/business_central/object/filter_query.rb +18 -0
  29. data/lib/business_central/object/general_ledger_entry.rb +13 -0
  30. data/lib/business_central/object/income_statement.rb +13 -0
  31. data/lib/business_central/object/irs1099_code.rb +16 -0
  32. data/lib/business_central/object/item.rb +16 -19
  33. data/lib/business_central/object/item_category.rb +16 -0
  34. data/lib/business_central/object/journal.rb +29 -0
  35. data/lib/business_central/object/journal_line.rb +48 -0
  36. data/lib/business_central/object/object_helper.rb +49 -0
  37. data/lib/business_central/object/payment_method.rb +16 -0
  38. data/lib/business_central/object/payment_term.rb +16 -0
  39. data/lib/business_central/object/picture.rb +53 -0
  40. data/lib/business_central/object/purchase_invoice.rb +8 -16
  41. data/lib/business_central/object/purchase_invoice_line.rb +14 -18
  42. data/lib/business_central/object/request.rb +61 -50
  43. data/lib/business_central/object/response.rb +31 -23
  44. data/lib/business_central/object/retained_earning_statement.rb +13 -0
  45. data/lib/business_central/object/sales_credit_memo.rb +20 -0
  46. data/lib/business_central/object/sales_credit_memo_line.rb +30 -0
  47. data/lib/business_central/object/sales_invoice.rb +62 -0
  48. data/lib/business_central/object/sales_invoice_line.rb +30 -0
  49. data/lib/business_central/object/sales_order.rb +20 -0
  50. data/lib/business_central/object/sales_order_line.rb +30 -0
  51. data/lib/business_central/object/sales_quote.rb +20 -0
  52. data/lib/business_central/object/sales_quote_line.rb +30 -0
  53. data/lib/business_central/object/shipment_method.rb +16 -0
  54. data/lib/business_central/object/subscription.rb +16 -0
  55. data/lib/business_central/object/tax_area.rb +16 -0
  56. data/lib/business_central/object/tax_group.rb +16 -0
  57. data/lib/business_central/object/time_registration_entry.rb +16 -0
  58. data/lib/business_central/object/trial_balance.rb +13 -0
  59. data/lib/business_central/object/units_of_measure.rb +16 -0
  60. data/lib/business_central/object/url_builder.rb +59 -0
  61. data/lib/business_central/object/url_helper.rb +44 -0
  62. data/lib/business_central/object/validation.rb +10 -7
  63. data/lib/business_central/object/vendor.rb +12 -15
  64. data/lib/business_central/object/vendor_purchase.rb +13 -0
  65. data/lib/business_central/version.rb +4 -2
  66. data/lib/business_central/web_service.rb +78 -0
  67. data/lib/core_ext/string.rb +18 -12
  68. data/test/business_central/client_test.rb +49 -7
  69. data/test/business_central/object/account_test.rb +6 -5
  70. data/test/business_central/object/aged_account_payable_test.rb +6 -5
  71. data/test/business_central/object/aged_account_receivable_test.rb +6 -5
  72. data/test/business_central/object/attachment_test.rb +117 -0
  73. data/test/business_central/object/balance_sheet_test.rb +6 -5
  74. data/test/business_central/object/base_test.rb +41 -0
  75. data/test/business_central/object/cash_flow_statement_test.rb +6 -5
  76. data/test/business_central/object/company_information_test.rb +9 -10
  77. data/test/business_central/object/company_test.rb +6 -5
  78. data/test/business_central/object/country_region_test.rb +129 -0
  79. data/test/business_central/object/currency_test.rb +150 -0
  80. data/test/business_central/object/customer_financial_detail_test.rb +68 -0
  81. data/test/business_central/object/customer_payment_journal_test.rb +134 -0
  82. data/test/business_central/object/customer_payment_test.rb +141 -0
  83. data/test/business_central/object/customer_sale_test.rb +72 -0
  84. data/test/business_central/object/customer_test.rb +168 -0
  85. data/test/business_central/object/default_dimension_test.rb +170 -0
  86. data/test/business_central/object/dimension_line_test.rb +165 -0
  87. data/test/business_central/object/dimension_test.rb +65 -0
  88. data/test/business_central/object/dimension_value_test.rb +68 -0
  89. data/test/business_central/object/employee_test.rb +141 -0
  90. data/test/business_central/object/filter_query_test.rb +36 -0
  91. data/test/business_central/object/general_ledger_entry_test.rb +82 -0
  92. data/test/business_central/object/income_statement_test.rb +82 -0
  93. data/test/business_central/object/irs1099_code_test.rb +124 -0
  94. data/test/business_central/object/item_category_test.rb +122 -0
  95. data/test/business_central/object/item_test.rb +16 -17
  96. data/test/business_central/object/journal_line_test.rb +152 -0
  97. data/test/business_central/object/journal_test.rb +144 -0
  98. data/test/business_central/object/payment_method_test.rb +134 -0
  99. data/test/business_central/object/payment_term_test.rb +134 -0
  100. data/test/business_central/object/picture_test.rb +74 -0
  101. data/test/business_central/object/purchase_invoice_line_test.rb +15 -15
  102. data/test/business_central/object/purchase_invoice_test.rb +15 -15
  103. data/test/business_central/object/request_test.rb +75 -12
  104. data/test/business_central/object/response_test.rb +34 -9
  105. data/test/business_central/object/retained_earning_statement_test.rb +52 -0
  106. data/test/business_central/object/sales_credit_memo_line_test.rb +134 -0
  107. data/test/business_central/object/sales_credit_memo_test.rb +146 -0
  108. data/test/business_central/object/sales_invoice_line_test.rb +164 -0
  109. data/test/business_central/object/sales_invoice_test.rb +156 -0
  110. data/test/business_central/object/sales_order_line_test.rb +134 -0
  111. data/test/business_central/object/sales_order_test.rb +146 -0
  112. data/test/business_central/object/sales_quote_line_test.rb +134 -0
  113. data/test/business_central/object/sales_quote_test.rb +146 -0
  114. data/test/business_central/object/shipment_method_test.rb +133 -0
  115. data/test/business_central/object/subscription_test.rb +126 -0
  116. data/test/business_central/object/tax_area_test.rb +126 -0
  117. data/test/business_central/object/tax_group_test.rb +126 -0
  118. data/test/business_central/object/time_registration_entry_test.rb +126 -0
  119. data/test/business_central/object/trial_balance_test.rb +82 -0
  120. data/test/business_central/object/units_of_measure_test.rb +126 -0
  121. data/test/business_central/object/validation_test.rb +5 -4
  122. data/test/business_central/object/vendor_purchase_test.rb +82 -0
  123. data/test/business_central/object/vendor_test.rb +16 -16
  124. data/test/business_central/web_service_test.rb +100 -0
  125. data/test/business_central_test.rb +3 -1
  126. data/test/test_helper.rb +16 -6
  127. metadata +188 -37
  128. data/lib/business_central/object/helper.rb +0 -15
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BusinessCentral
4
+ module Object
5
+ class ItemCategory < Base
6
+ OBJECT = 'itemCategories'
7
+
8
+ OBJECT_METHODS = %i[
9
+ get
10
+ post
11
+ patch
12
+ delete
13
+ ].freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BusinessCentral
4
+ module Object
5
+ class Journal < Base
6
+ extend BusinessCentral::Object::ObjectHelper
7
+
8
+ OBJECT = 'journals'
9
+
10
+ OBJECT_VALIDATION = {
11
+ code: {
12
+ maximum_length: 10
13
+ },
14
+ display_name: {
15
+ maximum_length: 50
16
+ }
17
+ }.freeze
18
+
19
+ OBJECT_METHODS = %i[
20
+ get
21
+ post
22
+ patch
23
+ delete
24
+ ].freeze
25
+
26
+ navigation :journal_line
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BusinessCentral
4
+ module Object
5
+ class JournalLine < Base
6
+ OBJECT = 'journalLines'
7
+
8
+ OBJECT_VALIDATION = {
9
+ account_number: {
10
+ maximum_length: 20
11
+ },
12
+ document_number: {
13
+ maximum_length: 20
14
+ },
15
+ external_document_number: {
16
+ maximum_length: 20
17
+ },
18
+ description: {
19
+ maximum_length: 50
20
+ },
21
+ comment: {
22
+ maximum_length: 250
23
+ }
24
+ }.freeze
25
+
26
+ OBJECT_METHODS = %i[
27
+ get
28
+ post
29
+ patch
30
+ delete
31
+ ].freeze
32
+
33
+ OBJECT_PARENTS = %w[
34
+ journals
35
+ ].freeze
36
+
37
+ def initialize(client, parent: 'journals', parent_id:, **args)
38
+ return if !valid_parent?(parent)
39
+
40
+ super(client, args)
41
+ @parent_path << {
42
+ path: parent,
43
+ id: parent_id
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BusinessCentral
4
+ module Object
5
+ module ObjectHelper
6
+ include ArgumentHelper
7
+
8
+ def object(object_name, *_params)
9
+ define_method(object_name) do |argument = nil|
10
+ object = "@#{object_name}_cache".to_sym
11
+ if argument.nil?
12
+ if !instance_variable_defined?(object)
13
+ instance_variable_set(
14
+ object,
15
+ BusinessCentral::Object.const_get(
16
+ object_name.to_s.to_camel_case(true).to_s.to_sym
17
+ ).new(self, argument)
18
+ )
19
+ else
20
+ instance_variable_get(object)
21
+ end
22
+ else
23
+ instance_variable_set(
24
+ object,
25
+ BusinessCentral::Object.const_get(
26
+ object_name.to_s.to_camel_case(true).to_s.to_sym
27
+ ).new(self, argument)
28
+ )
29
+ end
30
+ end
31
+ end
32
+
33
+ def navigation(object_name, *_params)
34
+ define_method(object_name) do |argument = nil|
35
+ object = "@#{object_name}_cache".to_sym
36
+ instance_variable_set(
37
+ object,
38
+ BusinessCentral::Object.const_get(object_name.to_s.to_camel_case(true).to_s.to_sym).new(
39
+ client,
40
+ company_id: company_id(argument),
41
+ parent: self.class.const_get(:OBJECT),
42
+ parent_id: id(argument)
43
+ )
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BusinessCentral
4
+ module Object
5
+ class PaymentMethod < Base
6
+ OBJECT = 'paymentMethods'
7
+
8
+ OBJECT_METHODS = %i[
9
+ get
10
+ post
11
+ patch
12
+ delete
13
+ ].freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BusinessCentral
4
+ module Object
5
+ class PaymentTerm < Base
6
+ OBJECT = 'paymentTerms'
7
+
8
+ OBJECT_METHODS = %i[
9
+ get
10
+ post
11
+ patch
12
+ delete
13
+ ].freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BusinessCentral
4
+ module Object
5
+ class Picture < Base
6
+ OBJECT = 'picture'
7
+
8
+ OBJECT_METHODS = %i[
9
+ get
10
+ post
11
+ patch
12
+ delete
13
+ ].freeze
14
+
15
+ OBJECT_PARENTS = %w[
16
+ items
17
+ customers
18
+ vendors
19
+ employees
20
+ ].freeze
21
+
22
+ def initialize(client, parent:, parent_id:, **args)
23
+ return if !valid_parent?(parent)
24
+
25
+ super(client, args)
26
+ @parent_path << {
27
+ path: parent,
28
+ id: parent_id
29
+ }
30
+ @parent_id = parent_id
31
+ end
32
+
33
+ def create(data)
34
+ url = "#{build_url(parent_path: @parent_path, child_path: object_name)}(#{@parent_id})/content"
35
+ Request.call(:patch, @client, url, etag: '', params: {}) do |request|
36
+ request['Content-Type'] = 'application/octet-stream'
37
+ request['If-Match'] = '*'
38
+ request.body = data
39
+ end
40
+ end
41
+
42
+ def update(data)
43
+ url = "#{build_url(parent_path: @parent_path, child_path: object_name)}(#{@parent_id})"
44
+ object = Request.get(@client, url)
45
+ url = "#{build_url(parent_path: @parent_path, child_path: object_name)}(#{@parent_id})/content"
46
+ Request.call(:patch, @client, url, etag: object[:etag], params: {}) do |request|
47
+ request['Content-Type'] = 'application/octet-stream'
48
+ request.body = data
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BusinessCentral
2
4
  module Object
3
5
  class PurchaseInvoice < Base
4
- OBJECT = 'purchaseInvoices'.freeze
6
+ OBJECT = 'purchaseInvoices'
5
7
 
6
8
  OBJECT_VALIDATION = {
7
9
  number: {
@@ -56,22 +58,12 @@ module BusinessCentral
56
58
  }
57
59
  }.freeze
58
60
 
59
- OBJECT_METHODS = [
60
- :get,
61
- :post,
62
- :patch,
63
- :delete
61
+ OBJECT_METHODS = %i[
62
+ get
63
+ post
64
+ patch
65
+ delete
64
66
  ].freeze
65
-
66
- def initialize(client, company_id:)
67
- super(client, company_id: company_id)
68
- @parent_path = [
69
- {
70
- path: 'companies',
71
- id: company_id
72
- }
73
- ]
74
- end
75
67
  end
76
68
  end
77
69
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BusinessCentral
2
4
  module Object
3
5
  class PurchaseInvoiceLine < Base
4
- OBJECT = 'purchaseInvoiceLines'.freeze
6
+ OBJECT = 'purchaseInvoiceLines'
5
7
 
6
8
  OBJECT_VALIDATION = {
7
9
  line_type: {
@@ -16,25 +18,19 @@ module BusinessCentral
16
18
  }
17
19
  }.freeze
18
20
 
19
- OBJECT_METHODS = [
20
- :get,
21
- :post,
22
- :patch,
23
- :delete
21
+ OBJECT_METHODS = %i[
22
+ get
23
+ post
24
+ patch
25
+ delete
24
26
  ].freeze
25
27
 
26
- def initialize(client, company_id:, purchase_invoice_id:)
27
- super(client, company_id: company_id)
28
- @parent_path = [
29
- {
30
- path: 'companies',
31
- id: company_id
32
- },
33
- {
34
- path: 'purchaseInvoices',
35
- id: purchase_invoice_id
36
- }
37
- ]
28
+ def initialize(client, purchase_invoice_id:, **args)
29
+ super(client, args)
30
+ @parent_path << {
31
+ path: 'purchaseInvoices',
32
+ id: purchase_invoice_id
33
+ }
38
34
  end
39
35
  end
40
36
  end
@@ -1,75 +1,86 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BusinessCentral
2
4
  module Object
3
5
  class Request
6
+ class << self
7
+ def get(client, url)
8
+ request(:get, client, url)
9
+ end
4
10
 
5
- def self.get(client, url)
6
- request(:get, client, url)
7
- end
8
-
9
- def self.post(client, url, params)
10
- request(:post, client, url, params: params)
11
- end
12
-
13
- def self.patch(client, url, etag, params)
14
- request(:patch, client, url, etag: etag, params: params)
15
- end
11
+ def post(client, url, params)
12
+ request(:post, client, url, params: params)
13
+ end
16
14
 
17
- def self.delete(client, url, etag)
18
- request(:delete, client, url, etag: etag)
19
- end
15
+ def patch(client, url, etag, params)
16
+ request(:patch, client, url, etag: etag, params: params)
17
+ end
20
18
 
21
- private
19
+ def delete(client, url, etag)
20
+ request(:delete, client, url, etag: etag)
21
+ end
22
22
 
23
- def self.request(method, client, url, etag: '', params: {})
24
- send do
25
- uri = URI(url)
26
- https = Net::HTTP.new(uri.host, uri.port);
27
- https.use_ssl = true
28
- request = Object.const_get("Net::HTTP::#{method.to_s.capitalize}").new(uri)
29
- request['Content-Type'] = 'application/json'
30
- request['Accept'] = 'application/json'
31
- request['If-Match'] = etag if !etag.blank?
32
- request.body = convert(params) if method == :post || method == :patch
33
- if client.access_token
34
- request['Authorization'] = "Bearer #{client.access_token.token}"
35
- else
36
- request.basic_auth(client.username, client.password)
23
+ def convert(request = {})
24
+ result = {}
25
+ request.each do |key, value|
26
+ result[key.to_s.to_camel_case] = value if key.is_a? Symbol
27
+ result[key.to_s] = value if key.is_a? String
37
28
  end
38
- https.request(request)
29
+
30
+ result.to_json
39
31
  end
40
- end
41
32
 
42
- def self.convert(request = {})
43
- result = {}
44
- request.each do |key, value|
45
- result[key.to_s.to_camel_case] = value
33
+ def request(method, client, url, etag: '', params: {})
34
+ send do
35
+ uri = URI(url)
36
+ https = Net::HTTP.new(uri.host, uri.port)
37
+ https.use_ssl = true
38
+ https.set_debug_output($stdout) if client.debug
39
+ request = Object.const_get("Net::HTTP::#{method.to_s.capitalize}").new(uri)
40
+ request['If-Match'] = etag if !etag.blank?
41
+ request['Accept'] = 'application/json'
42
+ if block_given?
43
+ yield(request)
44
+ else
45
+ request['Content-Type'] = 'application/json'
46
+ request.body = convert(params) if %i[post patch].include?(method)
47
+ end
48
+
49
+ if client.access_token
50
+ request['Authorization'] = "Bearer #{client.access_token.token}"
51
+ else
52
+ request.basic_auth(client.username, client.password)
53
+ end
54
+ https.request(request)
55
+ end
46
56
  end
57
+ alias call request
47
58
 
48
- return result.to_json
49
- end
59
+ private
50
60
 
51
- def self.send
52
- begin
61
+ def send
53
62
  request = yield
54
63
  response = Response.new(request.read_body.to_s).results
55
64
 
56
65
  if Response.success?(request.code.to_i)
57
- return response
58
- elsif Response.deleted?(request.code.to_i)
59
- return true
66
+ response
67
+ elsif Response.success_no_content?(request.code.to_i)
68
+ true
60
69
  else
61
70
  if Response.unauthorized?(request.code.to_i)
62
- raise UnauthorizedException.new
71
+ raise UnauthorizedException
72
+ elsif Response.not_found?(request.code.to_i)
73
+ raise NotFoundException
63
74
  else
64
- if response[:error][:code].present?
75
+ if !response.fetch(:error, nil).nil?
65
76
  case response[:error][:code]
66
- when 'Internal_CompanyNotFound'
67
- raise CompanyNotFoundException.new
68
- else
69
- raise ApiException.new("#{request.code} - #{response[:error][:code]} #{response[:error][:message]}")
77
+ when 'Internal_CompanyNotFound'
78
+ raise CompanyNotFoundException
79
+ else
80
+ raise ApiException, "#{request.code} - #{response[:error][:code]} #{response[:error][:message]}"
70
81
  end
71
82
  else
72
- raise ApiException.new("#{request.code} - API call failed")
83
+ raise ApiException, "#{request.code} - API call failed"
73
84
  end
74
85
  end
75
86
  end
@@ -77,4 +88,4 @@ module BusinessCentral
77
88
  end
78
89
  end
79
90
  end
80
- end
91
+ end