netsuite 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +1 -1
  3. data/HISTORY.md +35 -0
  4. data/README.md +2 -2
  5. data/lib/netsuite/actions/abstract_action.rb +32 -0
  6. data/lib/netsuite/actions/add.rb +5 -5
  7. data/lib/netsuite/actions/attach_file.rb +5 -5
  8. data/lib/netsuite/actions/delete.rb +14 -10
  9. data/lib/netsuite/actions/delete_list.rb +14 -10
  10. data/lib/netsuite/actions/get.rb +14 -10
  11. data/lib/netsuite/actions/get_all.rb +11 -7
  12. data/lib/netsuite/actions/get_deleted.rb +14 -10
  13. data/lib/netsuite/actions/get_list.rb +5 -5
  14. data/lib/netsuite/actions/get_select_value.rb +16 -8
  15. data/lib/netsuite/actions/initialize.rb +15 -11
  16. data/lib/netsuite/actions/search.rb +16 -19
  17. data/lib/netsuite/actions/update.rb +5 -5
  18. data/lib/netsuite/actions/update_list.rb +11 -7
  19. data/lib/netsuite/actions/upsert.rb +5 -5
  20. data/lib/netsuite/actions/upsert_list.rb +11 -7
  21. data/lib/netsuite/configuration.rb +3 -3
  22. data/lib/netsuite/records/estimate_item.rb +8 -1
  23. data/lib/netsuite/records/invoice.rb +3 -2
  24. data/lib/netsuite/records/vendor_return_authorization.rb +1 -1
  25. data/lib/netsuite/records/vendor_return_authorization_item.rb +1 -1
  26. data/lib/netsuite/support/requests.rb +0 -4
  27. data/lib/netsuite/support/search_result.rb +2 -1
  28. data/lib/netsuite/utilities.rb +4 -4
  29. data/lib/netsuite/version.rb +1 -1
  30. data/lib/netsuite.rb +1 -0
  31. data/spec/netsuite/actions/search_spec.rb +13 -30
  32. data/spec/netsuite/configuration_spec.rb +9 -1
  33. data/spec/netsuite/records/estimate_item_spec.rb +8 -1
  34. data/spec/netsuite/records/invoice_spec.rb +3 -2
  35. data/spec/netsuite/support/search_result_spec.rb +17 -0
  36. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5aad2f60c62b40aaa3e86460dc81283d470a3293d1568fe41d78e431b3d6ec61
4
- data.tar.gz: 411b9bbfaa28f9c76ad886245afe83334758d5b3b360d70e405bd1897a0c1a53
3
+ metadata.gz: 954fbfc75bb1bbce5dcae995d19a5cfc6cf862dc5b70c71ef445bdfb05321629
4
+ data.tar.gz: 959ea56ff63e5da0dfdb602a422dc8fd2dab8aecaf5742910f3d85e9333f7649
5
5
  SHA512:
6
- metadata.gz: 72ace4cda9656efd8592ed824ccb788c136aac912c5d9ec2fac38b817f00658979a29dae19c7a298108be49c9d1c386598a7476e05a61a25a05d18a53232c930
7
- data.tar.gz: 3fb702a8c3cca1c6896603769027022136b38af973820ae7f098d68f8ec0e4f07f45175d4b4cfd5fb8b189079f7a5ba5255becf166d0640bee5d067430ac3fe4
6
+ metadata.gz: 3470bae8218194017073f9ff4d52e781d0f5390b3d4b1c44e766fee8d13737da52f891f5f4ae9ce8e865d99d55fb47ebef0cedd115c64a908628ab65077a8940
7
+ data.tar.gz: ba3d6369e168926b02d51b2faa045bed59a7d4f45874e4a17dedec74f5f3c09d2ba356c962671b977c49412b4397d60017936323efc80a6340ed3fda119e6da4
@@ -7,7 +7,7 @@ jobs:
7
7
  runs-on: ubuntu-latest
8
8
  strategy:
9
9
  matrix:
10
- ruby-version: [3.1, 3.0, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1]
10
+ ruby-version: [3.2, 3.1, 3.0, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1]
11
11
  bundle-tzinfo: [true, false]
12
12
  env:
13
13
  BUNDLE_TZINFO: "${{ matrix.bundle-tzinfo }}"
data/HISTORY.md CHANGED
@@ -1,13 +1,45 @@
1
1
  ## Unreleased
2
2
 
3
+ ### Added
4
+
5
+ ### Fixed
6
+
7
+ ### Breaking Changes
8
+
9
+ ## v0.9.3
10
+
11
+ ### Added
12
+ * Create abstract action parent class by @andrewdicken-stripe in https://github.com/NetSweet/netsuite/pull/568
13
+
14
+ ### Fixed
15
+ * Add department, klass and location EstimateItem/record_refs by @nickdufresne in https://github.com/NetSweet/netsuite/pull/572
16
+ * Invoice shipping_tax_code should be a record_ref by @stevewoodcock in https://github.com/NetSweet/netsuite/pull/573
17
+ * dont crash if suitetalk returns empty <platformCore:searchRowList/> by @ericcj in https://github.com/NetSweet/netsuite/pull/574
18
+ * Add :klass field to record VendorReturnAuthorizationItem & VendorReturnAuthorization by @shubhrathasetty in https://github.com/NetSweet/netsuite/pull/576
19
+ * Optionally pass in `proxy` parameter to Savon by @dbecker-stripe in https://github.com/NetSweet/netsuite/pull/548
20
+
21
+ ## v0.9.2
22
+
23
+ ### Fixed
24
+
25
+ * Update rspec requirement from ~> 3.11.0 to ~> 3.12.0 by @dependabot in https://github.com/NetSweet/netsuite/pull/567
26
+ * [Adding UK country mapping](https://github.com/NetSweet/netsuite/commit/5fe96ed28fb8341b6926e169cf50d817632b5b8d)
27
+
28
+ ### Breaking Changes
29
+
30
+ * [remove country mapping hack for old API versions](https://github.com/NetSweet/netsuite/commit/a0357f0a9e08eb3a4a80f1d1e7a37f95bcb17d4f)
31
+
32
+ ## v0.9.1
3
33
 
4
34
  ### Added
5
35
  * Add `Configuration#multi_tenant!` for opting into multi-tentant support where configuration/caching is per-thread (#556)
6
36
 
7
37
  ### Fixed
8
38
  * Avoid Savon version `2.13.0` to prevent generating invalid envelopes. (#558, #563)
39
+ * Retry on `HTTPI::SSLError` and `HTTPI::TimeoutError` in backoff (#566)
9
40
 
10
41
  ### Breaking Changes
42
+ * Update default API version to 2016_2 from 2015_1 when `api_version` is not explicitly set (#554)
11
43
 
12
44
  ## 0.9.0
13
45
 
@@ -21,6 +53,9 @@ The following were removed as `fields` since their sublist class is not yet impl
21
53
  * Add `update` action to `File` records (#544)
22
54
  * Expose `errors` after calls to `delete` action (#545)
23
55
  * Add `update_list` action where missing on supported item records (#546)
56
+ * Add `proxy` attribute to `NetSuite::Configuration` to set a proxy used by the savon client (#547)
57
+
58
+ ### Fixed
24
59
  * Ignore `after_submit_failed` status details (>= 2018.2) when collating errors in add action (#550)
25
60
  * Add `NullFieldList` to `SalesOrder` (#552)
26
61
  * Add thread safety to NetSuite configuration and utilities (#549)
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [![Ruby](https://github.com/NetSweet/netsuite/actions/workflows/main.yml/badge.svg)](https://github.com/NetSweet/netsuite/actions/workflows/main.yml)
2
- [![Slack Status](https://opensuite-slackin.herokuapp.com/badge.svg)](http://opensuite-slackin.herokuapp.com)
2
+ [![Slack Status](https://netsuite-slackin.fly.dev/badge.svg)](https://netsuite-slackin.fly.dev)
3
3
  [![Gem Version](https://badge.fury.io/rb/netsuite.svg)](http://badge.fury.io/rb/netsuite)
4
4
 
5
5
  # NetSuite SuiteTalk API Ruby Gem
@@ -10,7 +10,7 @@
10
10
 
11
11
  # Help & Support
12
12
 
13
- Join the [Slack channel](http://opensuite-slackin.herokuapp.com) for help with any NetSuite issues. Please do not post usage questions as issues in GitHub.
13
+ Join the [Slack channel](https://netsuite-slackin.fly.dev) for help with any NetSuite issues. Please do not post usage questions as issues in GitHub.
14
14
 
15
15
  There is some additional helpful resources for NetSuite development [listed here](https://dashboard.suitesync.io/docs/resources#netsuite).
16
16
 
@@ -0,0 +1,32 @@
1
+ module NetSuite
2
+ module Actions
3
+ class AbstractAction
4
+ def request(credentials={})
5
+ NetSuite::Configuration.connection(request_options, credentials, soap_header_extra_info).call(action_name, message: request_body)
6
+ end
7
+
8
+ protected
9
+
10
+ def action_name
11
+ raise NotImplementedError, 'Not implemented on abstract class'
12
+ end
13
+
14
+ def initialize
15
+ raise NotImplementedError, 'Not implemented on abstract class'
16
+ end
17
+
18
+ def request_body
19
+ raise NotImplementedError, 'Not implemented on abstract class'
20
+ end
21
+
22
+ def request_options
23
+ {}
24
+ end
25
+
26
+ def soap_header_extra_info
27
+ {}
28
+ end
29
+ end
30
+ end
31
+ end
32
+
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/add.html
2
2
  module NetSuite
3
3
  module Actions
4
- class Add
4
+ class Add < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  attr_reader :response_hash
@@ -12,10 +12,6 @@ module NetSuite
12
12
 
13
13
  private
14
14
 
15
- def request(credentials={})
16
- NetSuite::Configuration.connection({}, credentials).call(:add, :message => request_body)
17
- end
18
-
19
15
  # <soap:Body>
20
16
  # <platformMsgs:add>
21
17
  # <platformMsgs:record xsi:type="listRel:Customer">
@@ -66,6 +62,10 @@ module NetSuite
66
62
  @response_hash ||= @response.to_hash[:add_response][:write_response]
67
63
  end
68
64
 
65
+ def action_name
66
+ :add
67
+ end
68
+
69
69
  def errors
70
70
  error_obj = response_hash[:status][:status_detail]
71
71
  error_obj = [error_obj] if error_obj.class == Hash
@@ -1,6 +1,6 @@
1
1
  module NetSuite
2
2
  module Actions
3
- class AttachFile
3
+ class AttachFile < AbstractAction
4
4
  include Support::Requests
5
5
 
6
6
  def initialize(object, file)
@@ -10,10 +10,6 @@ module NetSuite
10
10
 
11
11
  private
12
12
 
13
- def request(credentials = {})
14
- NetSuite::Configuration.connection({}, credentials).call(:attach, :message => request_body)
15
- end
16
-
17
13
  # <soap:Body>
18
14
  # <platformMsgs:attach>
19
15
  # <platformCore:attachReference xsi:type="platformCore:AttachContactReference">
@@ -60,6 +56,10 @@ module NetSuite
60
56
  @response_hash ||= @response.to_hash[:attach_response][:write_response]
61
57
  end
62
58
 
59
+ def action_name
60
+ :attach
61
+ end
62
+
63
63
  def errors
64
64
  error_obj = response_hash[:status][:status_detail]
65
65
  error_obj = [error_obj] if error_obj.class == Hash
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/delete.html
2
2
  module NetSuite
3
3
  module Actions
4
- class Delete
4
+ class Delete < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(object = nil, options = {})
@@ -11,15 +11,6 @@ module NetSuite
11
11
 
12
12
  private
13
13
 
14
- def request(credentials={})
15
- NetSuite::Configuration.connection(
16
- {namespaces: {
17
- 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
18
- 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
19
- }}, credentials
20
- ).call :delete, message: request_body
21
- end
22
-
23
14
  def soap_type
24
15
  NetSuite::Support::Records.netsuite_type(@object)
25
16
  end
@@ -71,6 +62,19 @@ module NetSuite
71
62
  end
72
63
  end
73
64
 
65
+ def request_options
66
+ {
67
+ namespaces: {
68
+ 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
69
+ 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
70
+ }
71
+ }
72
+ end
73
+
74
+ def action_name
75
+ :delete
76
+ end
77
+
74
78
  def errors
75
79
  error_obj = response_hash[:status][:status_detail]
76
80
  error_obj = [error_obj] if error_obj.class == Hash
@@ -1,6 +1,6 @@
1
1
  module NetSuite
2
2
  module Actions
3
- class DeleteList
3
+ class DeleteList < AbstractAction
4
4
  include Support::Requests
5
5
 
6
6
  def initialize(klass, options = { })
@@ -10,15 +10,6 @@ module NetSuite
10
10
 
11
11
  private
12
12
 
13
- def request(credentials={})
14
- NetSuite::Configuration.connection(
15
- {namespaces: {
16
- 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
17
- 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
18
- }}, credentials
19
- ).call :delete_list, message: request_body
20
- end
21
-
22
13
  # <soap:Body>
23
14
  # <platformMsgs:deleteList>
24
15
  # <platformMsgs:baseRef internalId="1" type="customer" xsi:type="platformCore:RecordRef"/>
@@ -71,6 +62,19 @@ module NetSuite
71
62
  end
72
63
  end
73
64
 
65
+ def request_options
66
+ {
67
+ namespaces: {
68
+ 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
69
+ 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
70
+ }
71
+ }
72
+ end
73
+
74
+ def action_name
75
+ :delete_list
76
+ end
77
+
74
78
  def errors
75
79
  errors = response_list.select { |r| r[:status] && r[:status][:status_detail] }.map do |obj|
76
80
  error_obj = obj[:status][:status_detail]
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/get.html
2
2
  module NetSuite
3
3
  module Actions
4
- class Get
4
+ class Get < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(klass, options = {})
@@ -11,15 +11,6 @@ module NetSuite
11
11
 
12
12
  private
13
13
 
14
- def request(credentials={})
15
- NetSuite::Configuration.connection(
16
- {namespaces: {
17
- 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
18
- 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
19
- }}, credentials
20
- ).call :get, message: request_body
21
- end
22
-
23
14
  def soap_type
24
15
  NetSuite::Support::Records.netsuite_type(@klass)
25
16
  end
@@ -56,6 +47,19 @@ module NetSuite
56
47
  @response_hash = @response.body[:get_response][:read_response]
57
48
  end
58
49
 
50
+ def request_options
51
+ {
52
+ namespaces: {
53
+ 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
54
+ 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
55
+ }
56
+ }
57
+ end
58
+
59
+ def action_name
60
+ :get
61
+ end
62
+
59
63
  module Support
60
64
 
61
65
  def self.included(base)
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/getAll.html
2
2
  module NetSuite
3
3
  module Actions
4
- class GetAll
4
+ class GetAll < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(klass)
@@ -10,12 +10,6 @@ module NetSuite
10
10
 
11
11
  private
12
12
 
13
- def request(credentials={})
14
- NetSuite::Configuration.connection(
15
- { element_form_default: :unqualified }, credentials
16
- ).call(:get_all, message: request_body)
17
- end
18
-
19
13
  # <soap:Body>
20
14
  # <platformMsgs:getAll>
21
15
  # <record>
@@ -49,6 +43,16 @@ module NetSuite
49
43
  @response_hash ||= @response.body[:get_all_response][:get_all_result]
50
44
  end
51
45
 
46
+ def request_options
47
+ {
48
+ element_form_default: :unqualified
49
+ }
50
+ end
51
+
52
+ def action_name
53
+ :get_all
54
+ end
55
+
52
56
  module Support
53
57
 
54
58
  def self.included(base)
@@ -1,6 +1,6 @@
1
1
  module NetSuite
2
2
  module Actions
3
- class GetDeleted
3
+ class GetDeleted < AbstractAction
4
4
  include Support::Requests
5
5
 
6
6
  def initialize(object = nil, options = {})
@@ -10,15 +10,6 @@ module NetSuite
10
10
 
11
11
  private
12
12
 
13
- def request(credentials={})
14
- NetSuite::Configuration.connection(
15
- {namespaces: {
16
- 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
17
- 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
18
- }}, credentials
19
- ).call :get_deleted, message: request_body
20
- end
21
-
22
13
  def soap_type
23
14
  NetSuite::Support::Records.netsuite_type(@object)
24
15
  end
@@ -72,6 +63,19 @@ module NetSuite
72
63
  @response_body ||= response_hash[:get_deleted_result]
73
64
  end
74
65
 
66
+ def request_options
67
+ {
68
+ namespaces: {
69
+ 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
70
+ 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
71
+ }
72
+ }
73
+ end
74
+
75
+ def action_name
76
+ :get_deleted
77
+ end
78
+
75
79
  module Support
76
80
  def self.included(base)
77
81
  base.extend(ClassMethods)
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/getList.html
2
2
  module NetSuite
3
3
  module Actions
4
- class GetList
4
+ class GetList < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(klass, options = { })
@@ -11,10 +11,6 @@ module NetSuite
11
11
 
12
12
  private
13
13
 
14
- def request(credentials={})
15
- NetSuite::Configuration.connection({}, credentials).call(:get_list, :message => request_body)
16
- end
17
-
18
14
  def request_body
19
15
  # list of all netsuite types; useful for debugging
20
16
  # https://webservices.netsuite.com/xsd/platform/v2014_1_0/coreTypes.xsd
@@ -64,6 +60,10 @@ module NetSuite
64
60
  @response_body
65
61
  end
66
62
 
63
+ def action_name
64
+ :get_list
65
+ end
66
+
67
67
  def success?
68
68
  # each returned record has its own status;
69
69
  if @options[:allow_incomplete]
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/getSelectValue.html
2
2
  module NetSuite
3
3
  module Actions
4
- class GetSelectValue
4
+ class GetSelectValue < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(klass, options = {})
@@ -11,13 +11,8 @@ module NetSuite
11
11
 
12
12
  private
13
13
 
14
- def request(credentials={})
15
- NetSuite::Configuration.connection(
16
- {namespaces: {
17
- 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
18
- 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
19
- }}, credentials
20
- ).call :get_select_value, :message => @options
14
+ def request_body
15
+ @options
21
16
  end
22
17
 
23
18
  def success?
@@ -32,6 +27,19 @@ module NetSuite
32
27
  @response_hash = @response.body[:get_select_value_response][:get_select_value_result]
33
28
  end
34
29
 
30
+ def request_options
31
+ {
32
+ namespaces: {
33
+ 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
34
+ 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
35
+ }
36
+ }
37
+ end
38
+
39
+ def action_name
40
+ :get_select_value
41
+ end
42
+
35
43
  module Support
36
44
 
37
45
  def self.included(base)
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/initializeinitializeList.html
2
2
  module NetSuite
3
3
  module Actions
4
- class Initialize
4
+ class Initialize < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(klass, object)
@@ -9,16 +9,6 @@ module NetSuite
9
9
  @object = object
10
10
  end
11
11
 
12
- def request(credentials={})
13
- NetSuite::Configuration.connection(
14
- {namespaces: {
15
- 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
16
- 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
17
- 'xmlns:platformCoreTyp' => "urn:types.core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
18
- }}, credentials
19
- ).call :initialize, :message => request_body
20
- end
21
-
22
12
  # <platformMsgs:initializeRecord>
23
13
  # <platformCore:type>invoice</platformCore:type>
24
14
  # <platformCore:reference internalId="1513" type="salesOrder">
@@ -52,6 +42,20 @@ module NetSuite
52
42
  @response_body ||= response_hash[:record]
53
43
  end
54
44
 
45
+ def request_options
46
+ {
47
+ namespaces: {
48
+ 'xmlns:platformMsgs' => "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
49
+ 'xmlns:platformCore' => "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
50
+ 'xmlns:platformCoreTyp' => "urn:types.core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com",
51
+ }
52
+ }
53
+ end
54
+
55
+ def action_name
56
+ :initialize
57
+ end
58
+
55
59
  module Support
56
60
 
57
61
  def self.included(base)
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/search.html
2
2
  module NetSuite
3
3
  module Actions
4
- class Search
4
+ class Search < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(klass, options = { })
@@ -18,24 +18,6 @@ module NetSuite
18
18
  end
19
19
 
20
20
  private
21
- def request(credentials={})
22
- # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/SettingSearchPreferences.html
23
- # https://webservices.netsuite.com/xsd/platform/v2012_2_0/messages.xsd
24
-
25
- preferences = NetSuite::Configuration.auth_header(credentials)
26
- .update(NetSuite::Configuration.soap_header)
27
- .merge(
28
- (@options.delete(:preferences) || {}).inject({'platformMsgs:SearchPreferences' => {}}) do |h, (k, v)|
29
- h['platformMsgs:SearchPreferences'][NetSuite::Utilities::Strings.lower_camelcase(k.to_s)] = v
30
- h
31
- end
32
- )
33
-
34
- NetSuite::Configuration
35
- .connection({ soap_header: preferences }, credentials)
36
- .call (@options.has_key?(:search_id)? :search_more_with_id : :search), :message => request_body
37
- end
38
-
39
21
  # basic search XML
40
22
 
41
23
  # <soap:Body>
@@ -239,6 +221,21 @@ module NetSuite
239
221
  end[:search_result]
240
222
  end
241
223
 
224
+ def action_name
225
+ @options.has_key?(:search_id)? :search_more_with_id : :search
226
+ end
227
+
228
+ def soap_header_extra_info
229
+ # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/SettingSearchPreferences.html
230
+ # https://webservices.netsuite.com/xsd/platform/v2012_2_0/messages.xsd
231
+
232
+ (@options.delete(:preferences) || {})
233
+ .inject({'platformMsgs:SearchPreferences' => {}}) do |h, (k, v)|
234
+ h['platformMsgs:SearchPreferences'][NetSuite::Utilities::Strings.lower_camelcase(k.to_s)] = v
235
+ h
236
+ end
237
+ end
238
+
242
239
  def success?
243
240
  @success ||= search_result[:status][:@is_success] == 'true'
244
241
  end
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/update.html
2
2
  module NetSuite
3
3
  module Actions
4
- class Update
4
+ class Update < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  attr_reader :response_hash
@@ -11,10 +11,6 @@ module NetSuite
11
11
  @attributes = attributes
12
12
  end
13
13
 
14
- def request(credentials={})
15
- NetSuite::Configuration.connection({}, credentials).call :update, :message => request_body
16
- end
17
-
18
14
  # <platformMsgs:update>
19
15
  # <platformMsgs:record internalId="980" xsi:type="listRel:Customer">
20
16
  # <listRel:companyName>Shutter Fly Corporation</listRel:companyName>
@@ -69,6 +65,10 @@ module NetSuite
69
65
  end
70
66
  end
71
67
 
68
+ def action_name
69
+ :update
70
+ end
71
+
72
72
  module Support
73
73
  def update(options = {}, credentials={})
74
74
  options[:internal_id] = internal_id if respond_to?(:internal_id) && internal_id
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/updateList.html
2
2
  module NetSuite
3
3
  module Actions
4
- class UpdateList
4
+ class UpdateList < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(*objects)
@@ -10,12 +10,6 @@ module NetSuite
10
10
 
11
11
  private
12
12
 
13
- def request(credentials={})
14
- NetSuite::Configuration.connection(
15
- { element_form_default: :unqualified }, credentials
16
- ).call(:update_list, message: request_body)
17
- end
18
-
19
13
  # <soap:Body>
20
14
  # <updateList>
21
15
  # <record xsi:type="listRel:Customer" externalId="ext1">
@@ -79,6 +73,16 @@ module NetSuite
79
73
  @success ||= response_hash.all? { |h| h[:status][:@is_success] == 'true' }
80
74
  end
81
75
 
76
+ def request_options
77
+ {
78
+ element_form_default: :unqualified
79
+ }
80
+ end
81
+
82
+ def action_name
83
+ :update_list
84
+ end
85
+
82
86
  module Support
83
87
 
84
88
  def self.included(base)
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/upsert.html
2
2
  module NetSuite
3
3
  module Actions
4
- class Upsert
4
+ class Upsert < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  attr_reader :response_hash
@@ -12,10 +12,6 @@ module NetSuite
12
12
 
13
13
  private
14
14
 
15
- def request(credentials={})
16
- NetSuite::Configuration.connection({}, credentials).call :upsert, :message => request_body
17
- end
18
-
19
15
  # <soap:Body>
20
16
  # <platformMsgs:upsert>
21
17
  # <platformMsgs:record xsi:type="listRel:Customer">
@@ -68,6 +64,10 @@ module NetSuite
68
64
  end
69
65
  end
70
66
 
67
+ def action_name
68
+ :upsert
69
+ end
70
+
71
71
  module Support
72
72
  def upsert(credentials={})
73
73
  response = NetSuite::Actions::Upsert.call([self], credentials)
@@ -1,7 +1,7 @@
1
1
  # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/upsertList.html
2
2
  module NetSuite
3
3
  module Actions
4
- class UpsertList
4
+ class UpsertList < AbstractAction
5
5
  include Support::Requests
6
6
 
7
7
  def initialize(*objects)
@@ -10,12 +10,6 @@ module NetSuite
10
10
 
11
11
  private
12
12
 
13
- def request(credentials={})
14
- NetSuite::Configuration.connection(
15
- { element_form_default: :unqualified }, credentials
16
- ).call(:upsert_list, message: request_body)
17
- end
18
-
19
13
  # <soap:Body>
20
14
  # <upsertList>
21
15
  # <record xsi:type="listRel:Customer" externalId="ext1">
@@ -75,6 +69,16 @@ module NetSuite
75
69
  @success ||= response_hash.all? { |h| h[:status][:@is_success] == 'true' }
76
70
  end
77
71
 
72
+ def request_options
73
+ {
74
+ element_form_default: :unqualified
75
+ }
76
+ end
77
+
78
+ def action_name
79
+ :upsert_list
80
+ end
81
+
78
82
  module Support
79
83
 
80
84
  def self.included(base)
@@ -18,21 +18,21 @@ module NetSuite
18
18
  end
19
19
  end
20
20
 
21
- def connection(params={}, credentials={})
21
+ def connection(params={}, credentials={}, soap_header_extra_info={})
22
22
  client = Savon.client({
23
23
  wsdl: cached_wsdl || wsdl,
24
24
  endpoint: endpoint,
25
25
  read_timeout: read_timeout,
26
26
  open_timeout: open_timeout,
27
27
  namespaces: namespaces,
28
- soap_header: auth_header(credentials).update(soap_header),
28
+ soap_header: auth_header(credentials).update(soap_header).merge(soap_header_extra_info),
29
29
  pretty_print_xml: true,
30
30
  filters: filters,
31
31
  logger: logger,
32
32
  log_level: log_level,
33
33
  log: !silent, # turn off logging entirely if configured
34
- proxy: proxy,
35
34
  }.update(params))
35
+ client.globals.proxy(proxy) if proxy
36
36
  cache_wsdl(client)
37
37
  return client
38
38
  end
@@ -13,7 +13,14 @@ module NetSuite
13
13
 
14
14
  field :custom_field_list, CustomFieldList
15
15
 
16
- record_refs :item, :job, :price, :tax_code, :units
16
+ record_refs :department,
17
+ :item,
18
+ :job,
19
+ :klass,
20
+ :location,
21
+ :price,
22
+ :tax_code,
23
+ :units
17
24
 
18
25
  def initialize(attributes_or_record = {})
19
26
  case attributes_or_record
@@ -25,7 +25,7 @@ module NetSuite
25
25
  :other_ref_num, :partners_list, :rev_rec_end_date,
26
26
  :rev_rec_on_rev_commitment, :rev_rec_schedule, :rev_rec_start_date, :revenue_status, :sales_effective_date,
27
27
  :sales_group, :sales_team_list, :ship_date, :ship_group_list,
28
- :shipping_cost, :shipping_tax_1_rate, :shipping_tax_2_rate, :shipping_tax_code, :source, :start_date,
28
+ :shipping_cost, :shipping_tax_1_rate, :shipping_tax_2_rate, :source, :start_date,
29
29
  :status, :sync_partner_teams, :sync_sales_teams, :tax_2_total,
30
30
  :tax_total, :time_disc_amount, :time_disc_print, :time_disc_rate, :time_disc_tax_1_amt, :time_disc_taxable,
31
31
  :time_discount, :time_list, :time_tax_code, :time_tax_rate_1, :time_tax_rate_2, :to_be_emailed, :to_be_faxed,
@@ -138,7 +138,8 @@ module NetSuite
138
138
 
139
139
  record_refs :account, :bill_address_list, :custom_form, :department, :entity, :klass, :partner,
140
140
  :posting_period, :ship_address_list, :terms, :location, :sales_rep, :tax_item, :created_from,
141
- :ship_method, :lead_source, :promo_code, :subsidiary, :currency, :approval_status, :job, :discount_item
141
+ :ship_method, :lead_source, :promo_code, :subsidiary, :currency, :approval_status, :job, :discount_item,
142
+ :shipping_tax_code
142
143
 
143
144
  attr_reader :internal_id
144
145
  attr_accessor :external_id
@@ -9,7 +9,7 @@ module NetSuite
9
9
 
10
10
  actions :get, :get_list, :add, :initialize, :delete, :update, :upsert, :search
11
11
 
12
- fields :billing_address, :created_date, :memo, :tran_date, :tran_id
12
+ fields :billing_address, :created_date, :memo, :tran_date, :tran_id, :klass
13
13
 
14
14
  record_refs :bill_address_list, :department, :entity, :location
15
15
 
@@ -8,7 +8,7 @@ module NetSuite
8
8
 
9
9
  fields :amortization_end_date, :amortization_residual, :amount, :bin_numbers, :description,
10
10
  :gross_amt, :is_billable, :is_closed, :is_drop_shipment, :line, :order_line, :quantity,
11
- :rate, :vendor_name
11
+ :rate, :vendor_name, :klass
12
12
 
13
13
  field :inventory_detail, InventoryDetail
14
14
 
@@ -22,10 +22,6 @@ module NetSuite
22
22
 
23
23
  private
24
24
 
25
- def request
26
- raise NotImplementedError, 'Please implement a #request method'
27
- end
28
-
29
25
  def build_response
30
26
  Response.new(success: success?, header: response_header, body: response_body, errors: response_errors)
31
27
  end
@@ -48,7 +48,8 @@ module NetSuite
48
48
  end
49
49
  elsif response.body.has_key? :search_row_list
50
50
  # advanced search results
51
- record_list = response.body[:search_row_list][:search_row]
51
+ record_list = response.body[:search_row_list]
52
+ record_list = record_list ? record_list[:search_row] : []
52
53
  record_list = [record_list] unless record_list.is_a?(Array)
53
54
 
54
55
  record_list.each do |record|
@@ -56,12 +56,12 @@ module NetSuite
56
56
  ns_record
57
57
  end
58
58
 
59
- def netsuite_server_time
60
- server_time_response = NetSuite::Utilities.backoff { NetSuite::Configuration.connection.call(:get_server_time) }
59
+ def netsuite_server_time(credentials={})
60
+ server_time_response = NetSuite::Utilities.backoff { NetSuite::Configuration.connection({}, credentials).call(:get_server_time) }
61
61
  server_time_response.body[:get_server_time_response][:get_server_time_result][:server_time]
62
62
  end
63
63
 
64
- def netsuite_data_center_urls(account_id)
64
+ def netsuite_data_center_urls(account_id, credentials={})
65
65
  data_center_call_response = NetSuite::Configuration.connection({
66
66
  # NOTE force a production WSDL so the sandbox settings are ignored
67
67
  # as of 1/20/18 NS will start using the account ID to determine
@@ -75,7 +75,7 @@ module NetSuite
75
75
  },
76
76
 
77
77
  soap_header: {}
78
- }).call(:get_data_center_urls, message: {
78
+ }, credentials).call(:get_data_center_urls, message: {
79
79
  'platformMsgs:account' => account_id
80
80
  })
81
81
 
@@ -1,3 +1,3 @@
1
1
  module NetSuite
2
- VERSION = '0.9.2'
2
+ VERSION = '0.9.3'
3
3
  end
data/lib/netsuite.rb CHANGED
@@ -48,6 +48,7 @@ module NetSuite
48
48
  end
49
49
 
50
50
  module Actions
51
+ autoload :AbstractAction, 'netsuite/actions/abstract_action'
51
52
  autoload :Add, 'netsuite/actions/add'
52
53
  autoload :AttachFile, 'netsuite/actions/attach_file'
53
54
  autoload :Delete, 'netsuite/actions/delete'
@@ -5,22 +5,29 @@ describe NetSuite::Actions::Search do
5
5
  after(:all) { savon.unmock! }
6
6
 
7
7
  it "handles custom auth credentials" do
8
- allow(NetSuite::Configuration).to receive(:connection).and_return(double().as_null_object)
9
-
10
8
  credentials = {
11
9
  email: 'fake@domain.com',
12
10
  password: 'fake'
13
11
  }
14
- NetSuite::Records::Customer.search({}, credentials)
15
12
 
16
- expect(NetSuite::Configuration).to have_received(:connection).with({:soap_header=>{
13
+ connection = NetSuite::Configuration.connection({}, credentials)
14
+
15
+ soap_header = {
17
16
  "platformMsgs:passport"=>{
18
17
  "platformCore:email"=>"fake@domain.com",
19
18
  "platformCore:password"=>"fake",
20
19
  "platformCore:account"=>"1234",
21
20
  "platformCore:role"=>{:@internalId=>"3"}
22
- }, "platformMsgs:SearchPreferences"=>{}}}, credentials
23
- )
21
+ }
22
+ }
23
+
24
+ expect(connection.instance_variable_get('@globals')[:soap_header]).to eq soap_header
25
+
26
+ allow(NetSuite::Configuration).to receive(:connection).and_return(double().as_null_object)
27
+
28
+ NetSuite::Records::Customer.search({}, credentials)
29
+
30
+ expect(NetSuite::Configuration).to have_received(:connection).with({}, credentials, { "platformMsgs:SearchPreferences"=>{} })
24
31
  end
25
32
 
26
33
  context "search class name" do
@@ -193,30 +200,6 @@ describe NetSuite::Actions::Search do
193
200
  expect(search.results.first.location_re_order_point).to eq('2565.0')
194
201
  expect(search.results.first.location_quantity_on_order).to eq('40000.0')
195
202
  end
196
-
197
- it "should handle an ID search with basic non-field result columns" do
198
- response = File.read('spec/support/fixtures/search/saved_search_item_2.xml')
199
- savon.expects(:search)
200
- .with(message: {
201
- "searchRecord"=>{
202
- "@xsi:type" =>"listAcct:ItemSearchAdvanced",
203
- "@savedSearchId" =>42,
204
- :content! =>{"listAcct:criteria"=>{}},
205
- }
206
- }).returns(response)
207
-
208
- search = NetSuite::Records::InventoryItem.search(saved: 42)
209
-
210
- results = search.results
211
- custom_fields = results.map do |record|
212
- record.custom_field_list.custom_fields.map(&:internal_id)
213
- end.flatten.uniq
214
- [
215
- :location_quantity_available,
216
- :location_re_order_point,
217
- :location_quantity_on_order,
218
- ].each {|field| expect(custom_fields).to include(field)}
219
- end
220
203
  end
221
204
 
222
205
  context "advanced search" do
@@ -519,13 +519,21 @@ describe NetSuite::Configuration do
519
519
  expect(config.proxy).to be_nil
520
520
  end
521
521
 
522
+ it 'does not pass in nil proxy to savon' do
523
+ connection = config.connection
524
+
525
+ expect(connection.globals.include?(:proxy)).to eql(false)
526
+ end
527
+
522
528
  it 'can be set with proxy=' do
523
529
  config.proxy = "https://my-proxy"
524
530
 
525
531
  expect(config.proxy).to eql("https://my-proxy")
526
532
 
527
533
  # ensure no exception is raised
528
- config.connection
534
+ connection = config.connection
535
+
536
+ expect(connection.globals.include?(:proxy)).to eql(true)
529
537
  end
530
538
 
531
539
  it 'can be set with proxy(value)' do
@@ -16,7 +16,14 @@ describe NetSuite::Records::EstimateItem do
16
16
 
17
17
  it 'has all the right record refs' do
18
18
  [
19
- :item, :job, :price, :tax_code, :units
19
+ :department,
20
+ :item,
21
+ :job,
22
+ :klass,
23
+ :location,
24
+ :price,
25
+ :tax_code,
26
+ :units,
20
27
  ].each do |record_ref|
21
28
  expect(item).to have_record_ref(record_ref)
22
29
  end
@@ -21,7 +21,7 @@ describe NetSuite::Records::Invoice do
21
21
  :other_ref_num, :partners_list, :rev_rec_end_date,
22
22
  :rev_rec_on_rev_commitment, :rev_rec_schedule, :rev_rec_start_date, :revenue_status, :sales_effective_date,
23
23
  :sales_group, :sales_team_list, :ship_address, :ship_date, :ship_group_list,
24
- :shipping_cost, :shipping_tax_1_rate, :shipping_tax_2_rate, :shipping_tax_code, :source, :start_date,
24
+ :shipping_cost, :shipping_tax_1_rate, :shipping_tax_2_rate, :source, :start_date,
25
25
  :status, :sync_partner_teams, :sync_sales_teams, :tax_2_total,
26
26
  :tax_total, :time_disc_amount, :time_disc_print, :time_disc_rate, :time_disc_tax_1_amt, :time_disc_taxable,
27
27
  :time_discount, :time_list, :time_tax_code, :time_tax_rate_1, :time_tax_rate_2, :to_be_emailed, :to_be_faxed,
@@ -151,7 +151,8 @@ describe NetSuite::Records::Invoice do
151
151
  it 'has the right record_refs' do
152
152
  [
153
153
  :account, :bill_address_list, :job, :custom_form, :department, :entity, :klass, :posting_period, :ship_address_list, :terms,
154
- :created_from, :location, :sales_rep, :ship_method, :tax_item, :partner, :lead_source, :promo_code, :subsidiary, :discount_item
154
+ :created_from, :location, :sales_rep, :ship_method, :tax_item, :partner, :lead_source, :promo_code, :subsidiary, :discount_item,
155
+ :shipping_tax_code
155
156
  ].each do |record_ref|
156
157
  expect(invoice).to have_record_ref(record_ref)
157
158
  end
@@ -22,6 +22,23 @@ describe NetSuite::Support::SearchResult do
22
22
  results = described_class.new(response, NetSuite::Actions::Search, {}).results
23
23
  expect(results).to eq []
24
24
  end
25
+
26
+ it 'returns empty search_row_list' do
27
+ response_body = {
28
+ :status => {:@is_success=>"true"},
29
+ :total_records => "242258",
30
+ :page_size => "10",
31
+ :total_pages => "24226",
32
+ :page_index => "99",
33
+ :search_id => "WEBSERVICES_4132604_SB1_051620191060155623420663266_336cbf12",
34
+ :search_row_list => nil,
35
+ :"@xmlns:platform_core" => "urn:core_2016_2.platform.webservices.netsuite.com"
36
+ }
37
+ response = NetSuite::Response.new(body: response_body)
38
+
39
+ results = described_class.new(response, NetSuite::Actions::Search, {}).results
40
+ expect(results).to eq []
41
+ end
25
42
  end
26
43
 
27
44
  it 'handles a recordList with a single element' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: netsuite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Moran
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-12-23 00:00:00.000000000 Z
13
+ date: 2023-03-27 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: savon
@@ -83,6 +83,7 @@ files:
83
83
  - README.md
84
84
  - Rakefile
85
85
  - lib/netsuite.rb
86
+ - lib/netsuite/actions/abstract_action.rb
86
87
  - lib/netsuite/actions/add.rb
87
88
  - lib/netsuite/actions/attach_file.rb
88
89
  - lib/netsuite/actions/delete.rb