From 800dfe7497edbc28fab1a7c67c5226143e450ec4 Mon Sep 17 00:00:00 2001 From: David Laprade Date: Tue, 19 Mar 2019 16:20:24 -0400 Subject: [PATCH 1/7] Clarify search row_list data components The "records" in the search group are hashes with "keys" that are the attribute names and "values" that the data returned by the search for those attributes (not necessarily the attribute values, though). For example, you'll often see things like this: ``` { :department=>{ :search_value=>{:@internal_id=>"113"}, :custom_label=>"Business Unit" } } ``` I think using `attr_name` and `search_result` instead of `k` and `v`, respectively, makes it clearer what the parts of this data constitute. --- lib/netsuite/support/search_result.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index 901c46edf..515188e35 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -59,11 +59,19 @@ def initialize(response, result_class, credentials) # skip all attributes: look for :basic and all :xxx_join next if search_group.to_s.start_with?('@') - record[search_group].each_pair do |k, v| + record[search_group].each_pair do |attr_name, search_result| + # example pair: + # { + # :department=>{ + # :search_value=>{:@internal_id=>"113"}, + # :custom_label=>"Business Unit" + # } + # } + # all return values are wrapped in a # extract the value from to make results easier to work with - if v.is_a?(Hash) && v.has_key?(:search_value) + if search_result.is_a?(Hash) && search_result.has_key?(:search_value) # Here's an example of a record ref and string response # @@ -78,7 +86,7 @@ def initialize(response, result_class, credentials) # attribute will be transitioned to the parent, and in the case # of a string response the parent node's value will be to the string - record[search_group][k] = v[:search_value] + record[search_group][attr_name] = search_result[:search_value] else # NOTE need to understand this case more, in testing, only the namespace definition hits this condition end From cb80a8fd0d866b7a5fbb07ebab4b0a01d1e6ff98 Mon Sep 17 00:00:00 2001 From: David Laprade Date: Wed, 20 Mar 2019 11:48:30 -0400 Subject: [PATCH 2/7] Expose non-field search results within custom field list Sometimes NS makes information available within saved search results that are not record fields. For example, you can run an InventoryItem search through the GUI that returns: * `Location Available` (the quantity available at the default location) * `Location Reorder Point` (quantity at which you should reorder) * `Location On Order` (quantity on order for the location) These are not record fields, as you can see with a quick CTRL-f through the NS schema docs: http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2018_2/schema/record/inventoryitem.html They aren't custom formula results either (which NS doesn't seem to expose through the API). And they also aren't _custom fields_. This information is just default, standard-issue NetSuite. It's perfectly reasonable to have a search that returns them as results, and thus also reasonable to expect to be able to access them through the API. --- lib/netsuite/support/search_result.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index 515188e35..85685b3c4 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -86,7 +86,19 @@ def initialize(response, result_class, credentials) # attribute will be transitioned to the parent, and in the case # of a string response the parent node's value will be to the string - record[search_group][attr_name] = search_result[:search_value] + if result_class.fields.include?(attr_name) || search_group != :basic + # this is a record field, it will be picked up when we + # intialize the `result_class` + record[search_group][attr_name] = search_result[:search_value] + else + # not a record field -- treat it as if it were a custom field + # otherwise it will be lost when we initialize + record[search_group][:custom_field_list] ||= {custom_field: []} + custom_fields = record[search_group][:custom_field_list][:custom_field] + custom_fields = [custom_fields] if custom_fields.is_a?(Hash) + custom_fields << search_result.merge(internal_id: attr_name) + record[search_group][:custom_field_list][:custom_field] = custom_fields + end else # NOTE need to understand this case more, in testing, only the namespace definition hits this condition end From 0784733302dff28c83a2d9feb0a4f0d517b89964 Mon Sep 17 00:00:00 2001 From: David Laprade Date: Wed, 20 Mar 2019 12:01:01 -0400 Subject: [PATCH 3/7] Don't attempt to modify object while iterating through it --- lib/netsuite/support/search_result.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index 85685b3c4..ae6ce44be 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -59,6 +59,9 @@ def initialize(response, result_class, credentials) # skip all attributes: look for :basic and all :xxx_join next if search_group.to_s.start_with?('@') + # avoids `RuntimeError: can't add a new key into hash during iteration` + record[search_group][:custom_field_list] ||= {custom_field: []} + record[search_group].each_pair do |attr_name, search_result| # example pair: # { @@ -93,7 +96,6 @@ def initialize(response, result_class, credentials) else # not a record field -- treat it as if it were a custom field # otherwise it will be lost when we initialize - record[search_group][:custom_field_list] ||= {custom_field: []} custom_fields = record[search_group][:custom_field_list][:custom_field] custom_fields = [custom_fields] if custom_fields.is_a?(Hash) custom_fields << search_result.merge(internal_id: attr_name) From a8530757cebf6c4e4a320813b2982888fa528eb0 Mon Sep 17 00:00:00 2001 From: David Laprade Date: Wed, 20 Mar 2019 12:39:30 -0400 Subject: [PATCH 4/7] Test that non-field information returned by searches is not lost --- spec/netsuite/actions/search_spec.rb | 22 + .../fixtures/search/saved_search_item.xml | 1671 +++++++++++++++++ 2 files changed, 1693 insertions(+) create mode 100644 spec/support/fixtures/search/saved_search_item.xml diff --git a/spec/netsuite/actions/search_spec.rb b/spec/netsuite/actions/search_spec.rb index a3cbfea04..83558d5e4 100644 --- a/spec/netsuite/actions/search_spec.rb +++ b/spec/netsuite/actions/search_spec.rb @@ -171,6 +171,28 @@ expect(search.results.first.alt_name).to eq('A Awesome Name') expect(search.results.last.email).to eq('alessawesome@gmail.com') end + + it "should handle an ID search with basic non-field result columns" do + response = File.read('spec/support/fixtures/search/saved_search_item.xml') + savon.expects(:search) + .with(message: { + "searchRecord"=>{ + "@xsi:type" =>"listAcct:ItemSearchAdvanced", + "@savedSearchId" =>42, + :content! =>{"listAcct:criteria"=>{}}, + } + }).returns(response) + search = NetSuite::Records::InventoryItem.search(saved: 42) + results = search.results + custom_fields = results.map do |record| + record.custom_field_list.custom_fields.map(&:internal_id) + end.flatten.uniq + [ + :location_quantity_available, + :location_re_order_point, + :location_quantity_on_order, + ].each {|field| expect(custom_fields).to include(field)} + end end context "advanced search" do diff --git a/spec/support/fixtures/search/saved_search_item.xml b/spec/support/fixtures/search/saved_search_item.xml new file mode 100644 index 000000000..6bbe4c058 --- /dev/null +++ b/spec/support/fixtures/search/saved_search_item.xml @@ -0,0 +1,1671 @@ + + + + WEBSERVICES_3603333_SB1_0320201916835580962038419462_2ce0aa2 + + + + + + + 49 + 1000 + 1 + 1 + WEBSERVICES_3603333_SB1_0320201916835580962038419462_2ce0aa2 + + + + + + Business Unit + + + 9781945179761 + SKU + + + 2.0 + Qty - Available + + + 32.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781945179747 + SKU + + + 3307.0 + Qty - Available + + + 40000.0 + Qty - On Order + + + 2565.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781945179730 + SKU + + + 3838.0 + Qty - Available + + + 45000.0 + Qty - On Order + + + 3507.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-04T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781945179716 + SKU + + + 2748.0 + Qty - Available + + + 1995.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781945179693 + SKU + + + 7520.0 + Qty - On Order + + + 3640.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-24T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781945179600 + SKU + + + 11334.0 + Qty - Available + + + 19366.0 + Qty - Reorder Point + + + + + Product Line + + + + + + + + + Business Unit + + + 9781945179419 + SKU + + + 24525.0 + Qty - Available + + + 50000.0 + Qty - On Order + + + 25035.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-24T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781945179259 + SKU + + + 1256.0 + Qty - Available + + + 7000.0 + Qty - On Order + + + 1583.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-29T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781945179150 + SKU + + + 17864.0 + Qty - Available + + + 3381.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781945179051 + SKU + + + 346.0 + Qty - Available + + + 75.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940999 + SKU + + + 821.0 + Qty - Available + + + 5000.0 + Qty - On Order + + + 1993.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940982 + SKU + + + 13163.0 + Qty - Available + + + 80000.0 + Qty - On Order + + + 20208.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-29T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940883 + SKU + + + 12554.0 + Qty - Available + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940876 + SKU + + + 19748.0 + Qty - Available + + + 7656.0 + Qty - Reorder Point + + + + + Product Line + + + 2018-08-16T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940852 + SKU + + + 2051.0 + Qty - Available + + + 2500.0 + Qty - On Order + + + 2622.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-01T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940845 + SKU + + + 1195.0 + Qty - Available + + + 2063.0 + Qty - On Order + + + 1180.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-13T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940722 + SKU + + + 4786.0 + Qty - Available + + + 669.0 + Qty - Reorder Point + + + + + Product Line + + + 2017-04-10T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940562 + SKU + + + 2720.0 + Qty - Available + + + 26000.0 + Qty - On Order + + + 2316.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-05-13T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940555 + SKU + + + 4438.0 + Qty - Available + + + 22000.0 + Qty - On Order + + + 3306.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-05-14T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940517 + SKU + + + 497.0 + Qty - Available + + + 234.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940340 + SKU + + + 911.0 + Qty - Available + + + 1000.0 + Qty - On Order + + + 363.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-13T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940197 + SKU + + + 1117.0 + Qty - Available + + + 357.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781935940166 + SKU + + + 330.0 + Qty - Available + + + 1000.0 + Qty - On Order + + + 157.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-05-21T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781934217962 + SKU + + + 615.0 + Qty - Available + + + 1000.0 + Qty - On Order + + + 238.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-13T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781934217894 + SKU + + + 1576.0 + Qty - Available + + + 829.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781934217795 + SKU + + + 2199.0 + Qty - Available + + + 567.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781934217757 + SKU + + + 120.0 + Qty - Available + + + 500.0 + Qty - On Order + + + 139.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-24T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781934217610 + SKU + + + 171.0 + Qty - Available + + + 1000.0 + Qty - On Order + + + 162.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-14T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781934217566 + SKU + + + 999.0 + Qty - Available + + + 2000.0 + Qty - On Order + + + 534.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-06-03T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 9781934217160 + SKU + + + 59.0 + Qty - Available + + + 500.0 + Qty - On Order + + + 164.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-01T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661015476 + SKU + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661015469 + SKU + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661015421 + SKU + + + 1394.0 + Qty - Available + + + 210.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-10T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661015360 + SKU + + + 5.0 + Qty - Available + + + 200.0 + Qty - On Order + + + 75.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-21T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661015322 + SKU + + + 10.0 + Qty - Available + + + 35.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661015148 + SKU + + + 445.0 + Qty - Available + + + 200.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661014950 + SKU + + + 359.0 + Qty - Available + + + 500.0 + Qty - On Order + + + 94.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-27T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661014851 + SKU + + + 151.0 + Qty - Available + + + 400.0 + Qty - On Order + + + 184.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-31T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661014844 + SKU + + + 142.0 + Qty - Available + + + 250.0 + Qty - On Order + + + 144.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-04-16T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661013861 + SKU + + + 103.0 + Qty - Available + + + 500.0 + Qty - On Order + + + 275.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-06T22:00:00.000-08:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661013809 + SKU + + + 49.0 + Qty - Available + + + 50.0 + Qty - Reorder Point + + + + + Product Line + + + + + + + + + Business Unit + + + 811661013779 + SKU + + + 734.0 + Qty - Available + + + 175.0 + Qty - Reorder Point + + + + + Product Line + + + 2018-09-10T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661013694 + SKU + + + 5715.0 + Qty - Available + + + 5813.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 8116610135956 + SKU + + + 354.0 + Qty - Available + + + 265.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661013427 + SKU + + + 13231.0 + Qty - Available + + + 4134.0 + Qty - Reorder Point + + + + + Product Line + + + 2018-08-16T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661010952 + SKU + + + 49.0 + Qty - Available + + + 13.0 + Qty - Reorder Point + + + + + Product Line + + + 2017-02-09T22:00:00.000-08:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661010594 + SKU + + + 81.0 + Qty - Available + + + 200.0 + Qty - On Order + + + 65.0 + Qty - Reorder Point + + + + + Product Line + + + 2019-03-27T22:00:00.000-07:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661010266 + SKU + + + 102.0 + Qty - Available + + + 59.0 + Qty - Reorder Point + + + + + Product Line + + + 2017-02-21T22:00:00.000-08:00 + Warehouse Date (Estimated) + + + + Reorder Status + + + + + + + + + Business Unit + + + 811661010044 + SKU + + + 425.0 + Qty - Available + + + 331.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + From 763b77ed4048284cd8a978f65fd3aa94a6d44e9e Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Sat, 13 Feb 2021 17:01:27 -0500 Subject: [PATCH 5/7] Restore extracting internal_id and support extracting external_id from search results after supporting non-record fields Since these aren't "fields" (they're plain ruby attributes), they were treated as non-standard fields and populated as custom fields. --- lib/netsuite/support/search_result.rb | 6 +++++- spec/netsuite/actions/search_spec.rb | 10 ++++++++++ spec/support/fixtures/search/saved_search_item.xml | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index ae6ce44be..f2ae543c6 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -89,7 +89,7 @@ def initialize(response, result_class, credentials) # attribute will be transitioned to the parent, and in the case # of a string response the parent node's value will be to the string - if result_class.fields.include?(attr_name) || search_group != :basic + if %i[internal_id external_id].include?(attr_name) || result_class.fields.include?(attr_name) || search_group != :basic # this is a record field, it will be picked up when we # intialize the `result_class` record[search_group][attr_name] = search_result[:search_value] @@ -111,6 +111,10 @@ def initialize(response, result_class, credentials) record[:basic][:internal_id] = record[:basic][:internal_id][:@internal_id] end + if record[:basic][:external_id] + record[:basic][:external_id] = record[:basic][:external_id][:@external_id] + end + result_wrapper = result_class.new(record.delete(:basic)) result_wrapper.search_joins = record results << result_wrapper diff --git a/spec/netsuite/actions/search_spec.rb b/spec/netsuite/actions/search_spec.rb index 83558d5e4..6429f089d 100644 --- a/spec/netsuite/actions/search_spec.rb +++ b/spec/netsuite/actions/search_spec.rb @@ -184,6 +184,11 @@ }).returns(response) search = NetSuite::Records::InventoryItem.search(saved: 42) results = search.results + + result = results.first + expect(result.internal_id).to eq('123') + expect(result.external_id).to eq('456') + custom_fields = results.map do |record| record.custom_field_list.custom_fields.map(&:internal_id) end.flatten.uniq @@ -192,6 +197,11 @@ :location_re_order_point, :location_quantity_on_order, ].each {|field| expect(custom_fields).to include(field)} + + [ + :internal_id, + :external_id, + ].each {|field| expect(custom_fields).to_not include(field)} end end diff --git a/spec/support/fixtures/search/saved_search_item.xml b/spec/support/fixtures/search/saved_search_item.xml index 6bbe4c058..b988c7666 100644 --- a/spec/support/fixtures/search/saved_search_item.xml +++ b/spec/support/fixtures/search/saved_search_item.xml @@ -16,6 +16,12 @@ + + + + + + Business Unit From 6a0b4188f1ee92191a32f1f292fd96bfbf654e53 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Sat, 13 Feb 2021 19:53:47 -0500 Subject: [PATCH 6/7] Assign field name to script_id for API version 2013.2 and newer when treating non-standard search result fields as custom fields --- lib/netsuite/records/custom_field_list.rb | 6 +- lib/netsuite/support/search_result.rb | 2 +- spec/netsuite/actions/search_spec.rb | 71 +++++++++++++++-------- 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/lib/netsuite/records/custom_field_list.rb b/lib/netsuite/records/custom_field_list.rb index 81a7cc555..6ae2ba3ae 100644 --- a/lib/netsuite/records/custom_field_list.rb +++ b/lib/netsuite/records/custom_field_list.rb @@ -3,6 +3,10 @@ module Records class CustomFieldList include Namespaces::PlatformCore + def self.reference_id_type + Configuration.api_version >= '2013_2' ? :script_id : :internal_id + end + def initialize(attributes = {}) case attributes[:custom_field] when Hash @@ -100,7 +104,7 @@ def to_record private def reference_id_type - @reference_id_type ||= Configuration.api_version >= '2013_2' ? :script_id : :internal_id + @reference_id_type ||= self.class.reference_id_type end def extract_custom_field(custom_field_data) diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index f2ae543c6..71a97dfee 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -98,7 +98,7 @@ def initialize(response, result_class, credentials) # otherwise it will be lost when we initialize custom_fields = record[search_group][:custom_field_list][:custom_field] custom_fields = [custom_fields] if custom_fields.is_a?(Hash) - custom_fields << search_result.merge(internal_id: attr_name) + custom_fields << search_result.merge(NetSuite::Records::CustomFieldList.reference_id_type => attr_name) record[search_group][:custom_field_list][:custom_field] = custom_fields end else diff --git a/spec/netsuite/actions/search_spec.rb b/spec/netsuite/actions/search_spec.rb index 6429f089d..34314eb1e 100644 --- a/spec/netsuite/actions/search_spec.rb +++ b/spec/netsuite/actions/search_spec.rb @@ -172,36 +172,57 @@ expect(search.results.last.email).to eq('alessawesome@gmail.com') end - it "should handle an ID search with basic non-field result columns" do - response = File.read('spec/support/fixtures/search/saved_search_item.xml') - savon.expects(:search) - .with(message: { + context "with basic non-field result columns" do + before do + savon.expects(:search).with(message: { "searchRecord"=>{ "@xsi:type" =>"listAcct:ItemSearchAdvanced", "@savedSearchId" =>42, :content! =>{"listAcct:criteria"=>{}}, } - }).returns(response) - search = NetSuite::Records::InventoryItem.search(saved: 42) - results = search.results - - result = results.first - expect(result.internal_id).to eq('123') - expect(result.external_id).to eq('456') - - custom_fields = results.map do |record| - record.custom_field_list.custom_fields.map(&:internal_id) - end.flatten.uniq - [ - :location_quantity_available, - :location_re_order_point, - :location_quantity_on_order, - ].each {|field| expect(custom_fields).to include(field)} - - [ - :internal_id, - :external_id, - ].each {|field| expect(custom_fields).to_not include(field)} + }).returns(File.read('spec/support/fixtures/search/saved_search_item.xml')) + end + + it "should handle an ID search" do + NetSuite::Configuration.api_version = '2013_1' + + search = NetSuite::Records::InventoryItem.search(saved: 42) + results = search.results + + result = results.first + expect(result.internal_id).to eq('123') + expect(result.external_id).to eq('456') + + custom_fields = results.map do |record| + record.custom_field_list.custom_fields.map(&:internal_id) + end.flatten.uniq + [ + :location_quantity_available, + :location_re_order_point, + :location_quantity_on_order, + ].each {|field| expect(custom_fields).to include(field)} + + [ + :internal_id, + :external_id, + ].each {|field| expect(custom_fields).to_not include(field)} + end + + it "uses script_id for custom fields when API >= 2013_2" do + NetSuite::Configuration.api_version = '2013_2' + + search = NetSuite::Records::InventoryItem.search(saved: 42) + results = search.results + + custom_fields = results.map do |record| + record.custom_field_list.custom_fields.map(&:script_id) + end.flatten.uniq + [ + :location_quantity_available, + :location_re_order_point, + :location_quantity_on_order, + ].each {|field| expect(custom_fields).to include(field)} + end end end From 8e1b4f4d0f9ad726fa282a728c951ec692326dfe Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Sun, 14 Feb 2021 15:48:31 -0500 Subject: [PATCH 7/7] Note how to access non-standard fields returned in search as custom fields in readme --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index 672fb4241..4be63fb7c 100644 --- a/README.md +++ b/README.md @@ -564,6 +564,33 @@ NetSuite::Records::CustomRecord.get_list( # do your thing... end +# If your search returns fields that aren't typically available on the record +# (ie. Invoice search can return close_date via TransactionSearchRowBasic, +# InventoryItem can return location_quantity_available via a saved search), +# those non-standard fields are available on the result object as custom fields: + +search = NetSuite::Records::Invoice.search( + criteria: { + basic: [ + { + field: 'type', + operator: 'anyOf', + value: ['_invoice'], + } + ], + }, + columns: { + 'tranSales:basic' => [ + 'platformCommon:internalId/' => {}, + 'platformCommon:closeDate/' => {}, + ] + }, +) + +search.results_in_batches do |batch| + puts batch.map { |invoice| invoice.custom_field_list.close_date.attributes.fetch(:search_value) } +end + # Adding a Customer Deposit example. The customer associated with the # sales order would be linked to the deposit.