business-central 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/lib/business_central.rb +35 -2
  3. data/lib/business_central/client.rb +65 -38
  4. data/lib/business_central/exceptions.rb +19 -9
  5. data/lib/business_central/object/account.rb +4 -2
  6. data/lib/business_central/object/aged_account_payable.rb +4 -2
  7. data/lib/business_central/object/aged_account_receivable.rb +4 -2
  8. data/lib/business_central/object/argument_helper.rb +22 -0
  9. data/lib/business_central/object/balance_sheet.rb +4 -2
  10. data/lib/business_central/object/base.rb +90 -56
  11. data/lib/business_central/object/cash_flow_statement.rb +4 -2
  12. data/lib/business_central/object/company.rb +5 -3
  13. data/lib/business_central/object/company_information.rb +7 -5
  14. data/lib/business_central/object/country_region.rb +8 -6
  15. data/lib/business_central/object/currency.rb +8 -6
  16. data/lib/business_central/object/customer.rb +15 -9
  17. data/lib/business_central/object/customer_financial_detail.rb +3 -1
  18. data/lib/business_central/object/customer_payment.rb +8 -6
  19. data/lib/business_central/object/customer_payment_journal.rb +8 -6
  20. data/lib/business_central/object/customer_sale.rb +3 -1
  21. data/lib/business_central/object/default_dimension.rb +17 -20
  22. data/lib/business_central/object/dimension.rb +20 -0
  23. data/lib/business_central/object/dimension_line.rb +37 -0
  24. data/lib/business_central/object/dimension_value.rb +28 -0
  25. data/lib/business_central/object/employee.rb +21 -0
  26. data/lib/business_central/object/filter_query.rb +18 -0
  27. data/lib/business_central/object/item.rb +17 -10
  28. data/lib/business_central/object/item_category.rb +16 -0
  29. data/lib/business_central/object/journal.rb +29 -0
  30. data/lib/business_central/object/journal_line.rb +48 -0
  31. data/lib/business_central/object/{helper.rb → object_helper.rb} +18 -10
  32. data/lib/business_central/object/payment_method.rb +16 -0
  33. data/lib/business_central/object/payment_term.rb +16 -0
  34. data/lib/business_central/object/picture.rb +53 -0
  35. data/lib/business_central/object/purchase_invoice.rb +8 -6
  36. data/lib/business_central/object/purchase_invoice_line.rb +10 -8
  37. data/lib/business_central/object/request.rb +60 -49
  38. data/lib/business_central/object/response.rb +28 -22
  39. data/lib/business_central/object/retained_earning_statement.rb +13 -0
  40. data/lib/business_central/object/sales_credit_memo.rb +20 -0
  41. data/lib/business_central/object/sales_credit_memo_line.rb +30 -0
  42. data/lib/business_central/object/sales_invoice.rb +62 -0
  43. data/lib/business_central/object/sales_invoice_line.rb +30 -0
  44. data/lib/business_central/object/sales_order.rb +20 -0
  45. data/lib/business_central/object/sales_order_line.rb +30 -0
  46. data/lib/business_central/object/sales_quote.rb +20 -0
  47. data/lib/business_central/object/sales_quote_line.rb +30 -0
  48. data/lib/business_central/object/shipment_method.rb +16 -0
  49. data/lib/business_central/object/subscription.rb +16 -0
  50. data/lib/business_central/object/tax_area.rb +16 -0
  51. data/lib/business_central/object/tax_group.rb +16 -0
  52. data/lib/business_central/object/time_registration_entry.rb +16 -0
  53. data/lib/business_central/object/trial_balance.rb +13 -0
  54. data/lib/business_central/object/units_of_measure.rb +16 -0
  55. data/lib/business_central/object/url_builder.rb +59 -0
  56. data/lib/business_central/object/url_helper.rb +32 -0
  57. data/lib/business_central/object/validation.rb +10 -7
  58. data/lib/business_central/object/vendor.rb +10 -7
  59. data/lib/business_central/object/vendor_purchase.rb +13 -0
  60. data/lib/business_central/version.rb +4 -2
  61. data/lib/business_central/web_service.rb +78 -0
  62. data/lib/core_ext/string.rb +18 -12
  63. data/test/business_central/client_test.rb +18 -11
  64. data/test/business_central/object/account_test.rb +6 -5
  65. data/test/business_central/object/aged_account_payable_test.rb +6 -5
  66. data/test/business_central/object/aged_account_receivable_test.rb +6 -5
  67. data/test/business_central/object/balance_sheet_test.rb +6 -5
  68. data/test/business_central/object/base_test.rb +4 -2
  69. data/test/business_central/object/cash_flow_statement_test.rb +6 -5
  70. data/test/business_central/object/company_information_test.rb +9 -10
  71. data/test/business_central/object/company_test.rb +6 -5
  72. data/test/business_central/object/country_region_test.rb +16 -17
  73. data/test/business_central/object/currency_test.rb +17 -18
  74. data/test/business_central/object/customer_financial_detail_test.rb +8 -6
  75. data/test/business_central/object/customer_payment_journal_test.rb +14 -15
  76. data/test/business_central/object/customer_payment_test.rb +15 -16
  77. data/test/business_central/object/customer_sale_test.rb +8 -6
  78. data/test/business_central/object/customer_test.rb +15 -16
  79. data/test/business_central/object/default_dimension_test.rb +15 -16
  80. data/test/business_central/object/dimension_line_test.rb +165 -0
  81. data/test/business_central/object/dimension_test.rb +65 -0
  82. data/test/business_central/object/dimension_value_test.rb +68 -0
  83. data/test/business_central/object/employee_test.rb +141 -0
  84. data/test/business_central/object/filter_query_test.rb +36 -0
  85. data/test/business_central/object/item_category_test.rb +122 -0
  86. data/test/business_central/object/item_test.rb +16 -17
  87. data/test/business_central/object/journal_line_test.rb +152 -0
  88. data/test/business_central/object/journal_test.rb +124 -0
  89. data/test/business_central/object/payment_method_test.rb +134 -0
  90. data/test/business_central/object/payment_term_test.rb +134 -0
  91. data/test/business_central/object/picture_test.rb +74 -0
  92. data/test/business_central/object/purchase_invoice_line_test.rb +15 -15
  93. data/test/business_central/object/purchase_invoice_test.rb +15 -15
  94. data/test/business_central/object/request_test.rb +17 -9
  95. data/test/business_central/object/response_test.rb +9 -7
  96. data/test/business_central/object/retained_earning_statement_test.rb +52 -0
  97. data/test/business_central/object/sales_credit_memo_line_test.rb +134 -0
  98. data/test/business_central/object/sales_credit_memo_test.rb +146 -0
  99. data/test/business_central/object/sales_invoice_line_test.rb +164 -0
  100. data/test/business_central/object/sales_invoice_test.rb +134 -0
  101. data/test/business_central/object/sales_order_line_test.rb +134 -0
  102. data/test/business_central/object/sales_order_test.rb +146 -0
  103. data/test/business_central/object/sales_quote_line_test.rb +134 -0
  104. data/test/business_central/object/sales_quote_test.rb +146 -0
  105. data/test/business_central/object/shipment_method_test.rb +133 -0
  106. data/test/business_central/object/subscription_test.rb +126 -0
  107. data/test/business_central/object/tax_area_test.rb +126 -0
  108. data/test/business_central/object/tax_group_test.rb +126 -0
  109. data/test/business_central/object/time_registration_entry_test.rb +126 -0
  110. data/test/business_central/object/trial_balance_test.rb +82 -0
  111. data/test/business_central/object/units_of_measure_test.rb +126 -0
  112. data/test/business_central/object/validation_test.rb +5 -4
  113. data/test/business_central/object/vendor_purchase_test.rb +82 -0
  114. data/test/business_central/object/vendor_test.rb +16 -16
  115. data/test/business_central/web_service_test.rb +95 -0
  116. data/test/business_central_test.rb +3 -1
  117. data/test/test_helper.rb +12 -6
  118. metadata +132 -33
@@ -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.downcase,
43
+ id: parent_id
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,14 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BusinessCentral
2
4
  module Object
3
- module Helper
4
- def object(object_name, *params)
5
- define_method(object_name) do |argument=nil|
5
+ module ObjectHelper
6
+ include ArgumentHelper
7
+
8
+ def object(object_name, *_params)
9
+ define_method(object_name) do |argument = nil|
6
10
  object = "@#{object_name}_cache".to_sym
7
11
  if argument.nil?
8
12
  if !instance_variable_defined?(object)
9
13
  instance_variable_set(
10
14
  object,
11
- BusinessCentral::Object.const_get("#{object_name.to_s.to_camel_case(true)}".to_sym).new(self, argument)
15
+ BusinessCentral::Object.const_get(
16
+ object_name.to_s.to_camel_case(true).to_s.to_sym
17
+ ).new(self, argument)
12
18
  )
13
19
  else
14
20
  instance_variable_get(object)
@@ -16,19 +22,21 @@ module BusinessCentral
16
22
  else
17
23
  instance_variable_set(
18
24
  object,
19
- BusinessCentral::Object.const_get("#{object_name.to_s.to_camel_case(true)}".to_sym).new(self, argument)
25
+ BusinessCentral::Object.const_get(
26
+ object_name.to_s.to_camel_case(true).to_s.to_sym
27
+ ).new(self, argument)
20
28
  )
21
29
  end
22
30
  end
23
31
  end
24
32
 
25
- def navigation(object_name, *params)
26
- define_method(object_name) do |argument=nil|
33
+ def navigation(object_name, *_params)
34
+ define_method(object_name) do |argument = nil|
27
35
  object = "@#{object_name}_cache".to_sym
28
36
  instance_variable_set(
29
37
  object,
30
- BusinessCentral::Object.const_get("#{object_name.to_s.to_camel_case(true)}".to_sym).new(
31
- self.client,
38
+ BusinessCentral::Object.const_get(object_name.to_s.to_camel_case(true).to_s.to_sym).new(
39
+ client,
32
40
  company_id: company_id(argument),
33
41
  parent: self.class.const_get(:OBJECT),
34
42
  parent_id: id(argument)
@@ -38,4 +46,4 @@ module BusinessCentral
38
46
  end
39
47
  end
40
48
  end
41
- 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.downcase,
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,11 +58,11 @@ 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
67
  end
66
68
  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,15 +18,15 @@ 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
+ def initialize(client, purchase_invoice_id:, **args)
29
+ super(client, args)
28
30
  @parent_path << {
29
31
  path: 'purchaseInvoices',
30
32
  id: purchase_invoice_id
@@ -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 if key.is_a? Symbol
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
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