business-central 1.0.0 → 1.0.5

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 +52 -2
  4. data/lib/business_central/client.rb +87 -39
  5. data/lib/business_central/exceptions.rb +30 -10
  6. data/lib/business_central/object/account.rb +4 -2
  7. data/lib/business_central/object/aged_account_payable.rb +13 -0
  8. data/lib/business_central/object/aged_account_receivable.rb +13 -0
  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 +13 -0
  12. data/lib/business_central/object/base.rb +100 -49
  13. data/lib/business_central/object/cash_flow_statement.rb +13 -0
  14. data/lib/business_central/object/company.rb +9 -2
  15. data/lib/business_central/object/company_information.rb +14 -0
  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 +28 -22
  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 +32 -0
  62. data/lib/business_central/object/validation.rb +11 -8
  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 +24 -5
  70. data/test/business_central/object/aged_account_payable_test.rb +61 -0
  71. data/test/business_central/object/aged_account_receivable_test.rb +61 -0
  72. data/test/business_central/object/attachment_test.rb +117 -0
  73. data/test/business_central/object/balance_sheet_test.rb +61 -0
  74. data/test/business_central/object/base_test.rb +41 -0
  75. data/test/business_central/object/cash_flow_statement_test.rb +61 -0
  76. data/test/business_central/object/company_information_test.rb +81 -0
  77. data/test/business_central/object/company_test.rb +24 -11
  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 -23
  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 -21
  102. data/test/business_central/object/purchase_invoice_test.rb +15 -21
  103. data/test/business_central/object/request_test.rb +75 -18
  104. data/test/business_central/object/response_test.rb +29 -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 -22
  124. data/test/business_central/web_service_test.rb +95 -0
  125. data/test/business_central_test.rb +3 -1
  126. data/test/test_helper.rb +16 -6
  127. metadata +199 -33
  128. data/lib/business_central/object/helper.rb +0 -15
@@ -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
@@ -1,29 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BusinessCentral
2
4
  module Object
3
5
  class Response
4
- attr_reader :results
6
+ class << self
7
+ def success?(status)
8
+ [200, 201].include?(status)
9
+ end
5
10
 
6
- def initialize(response)
7
- @results = nil
8
- if !response.blank?
9
- @response = JSON.parse(response)
10
- if @response.has_key?('value')
11
- @response = @response['value']
12
- end
13
- process
11
+ def success_no_content?(status)
12
+ status == 204
14
13
  end
15
- end
16
14
 
17
- def self.success?(status)
18
- status == 200 || status == 201
19
- end
15
+ def unauthorized?(status)
16
+ status == 401
17
+ end
20
18
 
21
- def self.deleted?(status)
22
- status == 204
19
+ def not_found?(status)
20
+ status == 404
21
+ end
23
22
  end
24
23
 
25
- def self.unauthorized?(status)
26
- status == 401
24
+ attr_reader :results
25
+
26
+ def initialize(response)
27
+ @results = nil
28
+ return if response.blank?
29
+
30
+ @response = JSON.parse(response)
31
+ @response = @response['value'] if @response.key?('value')
32
+ process
27
33
  end
28
34
 
29
35
  private
@@ -40,11 +46,11 @@ module BusinessCentral
40
46
  end
41
47
 
42
48
  def convert(data)
43
- result = {}
49
+ result = {}
44
50
  data.each do |key, value|
45
- if key == "@odata.etag"
51
+ if key == '@odata.etag'
46
52
  result[:etag] = value
47
- elsif key == "@odata.context"
53
+ elsif key == '@odata.context'
48
54
  result[:context] = value
49
55
  elsif value.is_a?(Hash)
50
56
  result[key.to_snake_case.to_sym] = convert(value)
@@ -53,8 +59,8 @@ module BusinessCentral
53
59
  end
54
60
  end
55
61
 
56
- return result
62
+ result
57
63
  end
58
64
  end
59
65
  end
60
- end
66
+ end