netsuite 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4706d84cf53e7897cc7f420a4af5c22230f764d0
4
- data.tar.gz: a0e4db30c9a0288633a73988b7bd74916a3dbc20
3
+ metadata.gz: 89b1dc6dad276f5db8f657634a3d125643ca198b
4
+ data.tar.gz: 586f0a9f83e7b1919a637a34f2d8fce536b8f2b4
5
5
  SHA512:
6
- metadata.gz: 2afc60b0287c25b4a9cb4d271a363da58c5089ee0eb60d10d6f2334b06ac1bd1bbd902fce592034f53f0fe0a600147184a51668b3bf7c903513d3a1c1e310069
7
- data.tar.gz: 5dadd1b9eae507ff201e01f3ab7f2d49e6e6a930d5ec1825fcc7ee2dd8087b71025a9e66700aa491b598a61606085b2c37a1f2f6f29457ade3693fe2809db925
6
+ metadata.gz: 76be28871d569715347328833f9521f8178879f17b93bb940fc10b9c960ef70652110ee85c4a277d02c6c21128f52c7cd762913331edcdacdc1463c853b81c7a
7
+ data.tar.gz: a9b49255201b452651df24646fc4d96e96b6d90b1b723a4170eb7f3fc276ea2f9281c609c440702be11e732f1a6e9145cfa67fdcb8537fca3c8f48d94d4057bb
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  vendor/
19
+ .tags*
data/Gemfile CHANGED
@@ -7,7 +7,8 @@ gem 'pry-nav'
7
7
  gem 'pry-rescue'
8
8
 
9
9
  # optional dependency for more accurate timezone conversion
10
- gem 'tzinfo'
10
+ gem 'tzinfo', '1.2.5'
11
+ # gem 'tzinfo', '2.0.0'
11
12
 
12
13
  # required for CircleCI to build properly with ruby 1.9.3
13
14
  gem 'json', '~> 1.8.3'
data/README.md CHANGED
@@ -60,14 +60,36 @@ This gem is built for ruby 1.9.x+, checkout the [1-8-stable](https://github.com/
60
60
 
61
61
  ## Configuration
62
62
 
63
- Not sure how to find your account id? Search for "web service preferences" in the NetSuite global search.
63
+ The most important thing you'll need is your NetSuite account ID. Not sure how to find your account id? [Here's a guide.](http://mikebian.co/find-netsuite-web-services-account-number/)
64
+
65
+ For most use-cases, the following configuration will be sufficient:
64
66
 
65
67
  ```ruby
66
68
  NetSuite.configure do
67
69
  reset!
68
70
 
69
- # optional, defaults to 2011_2
70
- api_version '2012_1'
71
+ account 'TSTDRV1576318'
72
+ api_version '2018_2'
73
+
74
+ email 'email@example.com'
75
+ password 'password'
76
+ role 10
77
+
78
+ # use `NetSuite::Utilities.netsuite_data_center_urls('TSTDRV1576318')` to retrieve the URL
79
+ # you'll want to do this in a background proces and strip the protocol out of the return string
80
+ wsdl_domain 'tstdrv1576318.suitetalk.api.netsuite.com'
81
+ end
82
+ ```
83
+
84
+ The `wsdl_domain` configuration is most important. Note that if you use `wsdl` or other configuration options below, you'll want to look at the configuration source to understand more about how the different options interact with each other. Some of the configuration options will mutate the state of other options.
85
+
86
+ Here's the various options that are are available for configuration:
87
+
88
+ ```ruby
89
+ NetSuite.configure do
90
+ reset!
91
+
92
+ api_version '2018_2'
71
93
 
72
94
  # optionally specify full wsdl URL (to switch to sandbox, for example)
73
95
  wsdl "https://webservices.sandbox.netsuite.com/wsdl/v#{api_version}_0/netsuite.wsdl"
@@ -79,21 +101,18 @@ NetSuite.configure do
79
101
  # construct the full wsdl location - e.g. "https://#{wsdl_domain}/wsdl/v#{api_version}_0/netsuite.wsdl"
80
102
  wsdl_domain "webservices.na2.netsuite.com"
81
103
 
82
- # or specify the sandbox flag if you don't want to deal with specifying a full URL
83
- sandbox true
84
-
85
104
  # often the netsuite servers will hang which would cause a timeout exception to be raised
86
- # if you don't mind waiting (e.g. processing NS via DJ), increasing the timeout should fix the issue
87
- read_timeout 100000
105
+ # if you don't mind waiting (e.g. processing NS via a background worker), increasing the timeout should fix the issue
106
+ read_timeout 100_000
88
107
 
89
108
  # you can specify a file or file descriptor to send the log output to (defaults to STDOUT)
90
109
  log File.join(Rails.root, 'log/netsuite.log')
91
110
 
92
- # login information
93
- email 'email@domain.com'
94
- password 'password'
111
+ # password-based login information
112
+ email 'email@domain.com'
113
+ password 'password'
95
114
  account '12345'
96
- role 1111
115
+ role 1111
97
116
 
98
117
  # optional, ensures that read-only fields don't cause API errors
99
118
  soap_header 'platformMsgs:preferences' => {
@@ -206,8 +206,10 @@ module NetSuite
206
206
  autoload :Location, 'netsuite/records/location'
207
207
  autoload :LocationsList, 'netsuite/records/locations_list'
208
208
  autoload :LotNumberedAssemblyItem, 'netsuite/records/lot_numbered_assembly_item'
209
+ autoload :LotNumberedInventoryItem, 'netsuite/records/lot_numbered_inventory_item'
209
210
  autoload :MatrixOptionList, 'netsuite/records/matrix_option_list'
210
211
  autoload :MemberList, 'netsuite/records/member_list'
212
+ autoload :Message, 'netsuite/records/message'
211
213
  autoload :NonInventorySaleItem, 'netsuite/records/non_inventory_sale_item'
212
214
  autoload :NonInventoryPurchaseItem, 'netsuite/records/non_inventory_purchase_item'
213
215
  autoload :NonInventoryResaleItem, 'netsuite/records/non_inventory_resale_item'
@@ -261,6 +263,7 @@ module NetSuite
261
263
  autoload :Subsidiary, 'netsuite/records/subsidiary'
262
264
  autoload :SubtotalItem, 'netsuite/records/subtotal_item'
263
265
  autoload :SupportCase, 'netsuite/records/support_case'
266
+ autoload :SupportCaseType, 'netsuite/records/support_case_type'
264
267
  autoload :TaxType, 'netsuite/records/tax_type'
265
268
  autoload :TaxGroup, 'netsuite/records/tax_group'
266
269
  autoload :Task, 'netsuite/records/task'
@@ -309,23 +312,4 @@ module NetSuite
309
312
  NetSuite::Configuration.instance_eval(&block)
310
313
  end
311
314
 
312
- def self.configure_from_env(&block)
313
- NetSuite.configure do
314
- reset!
315
-
316
- email ENV['NETSUITE_EMAIL'] unless ENV['NETSUITE_EMAIL'].nil?
317
- password ENV['NETSUITE_PASSWORD'] unless ENV['NETSUITE_PASSWORD'].nil?
318
- account ENV['NETSUITE_ACCOUNT'] unless ENV['NETSUITE_ACCOUNT'].nil?
319
- role ENV['NETSUITE_ROLE'] unless ENV['NETSUITE_ROLE'].nil?
320
- api_version ENV['NETSUITE_API'] unless ENV['NETSUITE_API'].nil?
321
- sandbox (ENV['NETSUITE_PRODUCTION'].nil? || ENV['NETSUITE_PRODUCTION'] != 'true')
322
- wsdl ENV['NETSUITE_WSDL'] unless ENV['NETSUITE_WSDL'].nil?
323
- silent (!ENV['NETSUITE_SILENT'].nil? && ENV['NETSUITE_SILENT'] == 'true')
324
-
325
- read_timeout 100_000
326
- end
327
-
328
- self.configure(&block) if block
329
- end
330
-
331
315
  end
@@ -28,6 +28,14 @@ module NetSuite
28
28
  # </platformCore:wsRoleList>
29
29
 
30
30
  def self.call(credentials)
31
+
32
+ soap_header = {}
33
+ if !credentials[:application_id].nil? && !credentials[:application_id].empty?
34
+ soap_header = NetSuite::Configuration.soap_header.dup
35
+ soap_header['platformMsgs:ApplicationInfo'] ||= {}
36
+ soap_header['platformMsgs:ApplicationInfo']['platformMsgs:applicationId'] = credentials[:application_id]
37
+ end
38
+
31
39
  passport = NetSuite::Configuration.auth_header.dup
32
40
 
33
41
 
@@ -39,13 +47,13 @@ module NetSuite
39
47
  if passport['platformMsgs:tokenPassport']
40
48
  passport['platformMsgs:passport']['platformCore:account'] ||= passport['platformMsgs:tokenPassport']['platformCore:account']
41
49
  end
42
-
50
+
43
51
  passport['platformMsgs:passport']['platformCore:account'] = credentials[:account] if !credentials[:account].nil?
44
52
 
45
53
  passport.delete('platformMsgs:tokenPassport')
46
54
 
47
55
  begin
48
- response = NetSuite::Configuration.connection(soap_header: {}).call :login, message: passport
56
+ response = NetSuite::Configuration.connection(soap_header: soap_header).call :login, message: passport
49
57
  rescue Savon::SOAPFault => e
50
58
  error_details = e.to_hash[:fault]
51
59
 
@@ -37,6 +37,8 @@ module NetSuite
37
37
  hash['platformMsgs:record']['@platformMsgs:externalId'] = @object.external_id
38
38
  end
39
39
 
40
+ # setting the internal ID on upsert will result in `CANT_SET_INTERNALID`
41
+
40
42
  hash
41
43
  end
42
44
 
@@ -18,6 +18,7 @@ module NetSuite
18
18
  client = Savon.client({
19
19
  wsdl: cached_wsdl || wsdl,
20
20
  read_timeout: read_timeout,
21
+ open_timeout: open_timeout,
21
22
  namespaces: namespaces,
22
23
  soap_header: auth_header(credentials).update(soap_header),
23
24
  pretty_print_xml: true,
@@ -326,6 +327,18 @@ module NetSuite
326
327
  end
327
328
  end
328
329
 
330
+ def open_timeout=(timeout)
331
+ attributes[:open_timeout] = timeout
332
+ end
333
+
334
+ def open_timeout(timeout = nil)
335
+ if timeout
336
+ self.open_timeout = timeout
337
+ else
338
+ attributes[:open_timeout]
339
+ end
340
+ end
341
+
329
342
  def log=(path)
330
343
  attributes[:log] = path
331
344
  end
@@ -0,0 +1,116 @@
1
+ module NetSuite
2
+ module Records
3
+ class LotNumberedInventoryItem
4
+ include Support::Fields
5
+ include Support::RecordRefs
6
+ include Support::Records
7
+ include Support::Actions
8
+ include Namespaces::ListAcct
9
+
10
+ # http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2018_2/schema/record/lotnumberedinventoryitem.html
11
+
12
+ # TODO
13
+ # countryOfManufacture Country
14
+ # hazmatPackingGroup HazmatPackingGroup
15
+ # accountingBookDetailList ItemAccountingBookDetailList
16
+ # costEstimateType ItemCostEstimateType
17
+ # costingMethod ItemCostingMethod
18
+ # invtClassification ItemInvtClassification
19
+ # matrixType ItemMatrixType
20
+ # itemOptionsList ItemOptionsList
21
+ # outOfStockBehavior ItemOutOfStockBehavior
22
+ # overallQuantityPricingType ItemOverallQuantityPricingType
23
+ # preferenceCriterion ItemPreferenceCriterion
24
+ # itemVendorList ItemVendorList
25
+ # weightUnit ItemWeightUnit
26
+ # hierarchyVersionsList LotNumberedInventoryItemHierarchyVersionsList
27
+ # numbersList LotNumberedInventoryItemNumbersList
28
+ # periodicLotSizeType PeriodicLotSizeType
29
+ # presentationItemList PresentationItemList
30
+ # productFeedList ProductFeedList
31
+
32
+ field :pricing_matrix, PricingMatrix
33
+ field :custom_field_list, CustomFieldList
34
+ field :bin_number_list, BinNumberList
35
+ field :locations_list, LocationsList
36
+ field :item_vendor_list, ItemVendorList
37
+ field :matrix_option_list, MatrixOptionList
38
+ field :subsidiary_list, RecordRefList
39
+
40
+ actions :get, :get_list, :add, :delete, :search, :update, :upsert, :update_list
41
+
42
+ record_refs :alternate_demand_source_item, :asset_account, :bill_exch_rate_variance_acct,
43
+ :billing_schedule, :bill_price_variance_acct, :bill_qty_variance_acct,
44
+ :klass, :cogs_account, :cost_category, :create_revenue_plans_on,
45
+ :custom_form, :default_item_ship_method, :deferred_revenue_account,
46
+ :demand_source, :department, :dropship_expense_account, :gain_loss_account,
47
+ :income_account, :interco_cogs_account, :interco_income_account,
48
+ :issue_product, :item_revenue_category, :location, :parent, :preferred_location,
49
+ :pricing_group, :purchase_price_variance_acct, :purchase_tax_code, :purchase_unit,
50
+ :quantity_pricing_schedule, :revenue_allocation_group, :revenue_recognition_rule,
51
+ :rev_rec_forecast_rule, :rev_rec_schedule, :sales_tax_code, :sale_unit,
52
+ :ship_package, :soft_descriptor, :stock_unit, :store_display_image,
53
+ :store_display_thumbnail, :store_item_template, :supply_lot_sizing_method,
54
+ :supply_replenishment_method, :supply_type, :tax_schedule, :units_type, :vendor
55
+
56
+ # TODO
57
+ # itemNumberOptionsList RecordRefList
58
+ # itemShipMethodList RecordRefList
59
+ # subsidiaryList RecordRefList
60
+ # scheduleBCode ScheduleBCode
61
+ # itemCarrier ShippingCarrier
62
+ # siteCategoryList SiteCategoryList
63
+ # sitemapPriority SitemapPriority
64
+ # translationsList TranslationList
65
+ # vsoeDeferral VsoeDeferral
66
+ # vsoePermitDiscount VsoePermitDiscount
67
+ # vsoeSopGroup VsoeSopGroup
68
+
69
+ fields :auto_lead_time, :auto_preferred_stock_level, :auto_reorder_point, :available_to_partners,
70
+ :copy_description, :direct_revenue_posting, :dont_show_price, :enforce_min_qty_internally,
71
+ :exclude_from_sitemap, :include_children, :is_donation_item, :is_drop_ship_item, :is_gco_compliant,
72
+ :is_hazmat_item, :is_inactive, :is_online, :is_special_order_item, :is_store_pickup_allowed,
73
+ :is_taxable, :match_bill_to_receipt, :mult_manufacture_addr, :offer_support, :on_special,
74
+ :prices_include_tax, :producer, :round_up_as_component, :seasonal_demand, :ship_individually,
75
+ :show_default_donation_amount, :track_landed_cost, :use_bins, :use_marginal_rates, :vsoe_delivered,
76
+ :created_date, :expiration_date, :last_invt_count_date, :last_modified_date, :next_invt_count_date,
77
+ :average_cost, :cost, :cost_estimate, :default_return_cost, :demand_modifier, :fixed_lot_size,
78
+ :handling_cost, :hazmat_item_units_qty, :last_purchase_price, :max_donation_amount,
79
+ :on_hand_value_mli, :preferred_stock_level, :preferred_stock_level_days, :purchase_order_amount,
80
+ :purchase_order_quantity, :purchase_order_quantity_diff, :quantity_available,
81
+ :quantity_back_ordered, :quantity_committed, :quantity_on_hand, :quantity_on_order,
82
+ :rate, :receipt_amount, :receipt_quantity, :receipt_quantity_diff, :reorder_point,
83
+ :safety_stock_level, :shipping_cost, :total_value, :transfer_price, :vsoe_price,
84
+ :weight, :backward_consumption_days, :demand_time_fence, :forward_consumption_days,
85
+ :invt_count_interval, :lead_time, :maximum_quantity, :minimum_quantity, :periodic_lot_size_days,
86
+ :reorder_multiple, :reschedule_in_days, :reschedule_out_days, :safety_stock_level_days,
87
+ :schedule_b_quantity, :shopzilla_category_id, :supply_time_fence, :costing_method_display,
88
+ :cost_units, :currency, :display_name, :featured_description, :handling_cost_units,
89
+ :hazmat_hazard_class, :hazmat_id, :hazmat_item_units, :hazmat_shipping_name, :item_id,
90
+ :manufacturer, :manufacturer_addr1, :manufacturer_city, :manufacturer_state,
91
+ :manufacturer_tariff, :manufacturer_tax_id, :manufacturer_zip, :matrix_item_name_template,
92
+ :meta_tag_html, :minimum_quantity_units, :mpn, :nex_tag_category, :no_price_message,
93
+ :out_of_stock_message, :page_title, :preferred_stock_level_units, :purchase_description,
94
+ :quantity_on_hand_units, :quantity_reorder_units, :related_items_description,
95
+ :reorder_point_units, :safety_stock_level_units, :sales_description, :schedule_b_number,
96
+ :search_keywords, :serial_numbers, :shipping_cost_units, :shopping_dot_com_category,
97
+ :specials_description, :stock_description, :store_description, :store_detailed_description,
98
+ :store_display_name, :upc_code, :url_component, :vendor_name, :weight_units
99
+
100
+
101
+ attr_reader :internal_id
102
+ attr_accessor :external_id, :search_joins
103
+
104
+ def initialize(attributes = {})
105
+ @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
106
+ @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
107
+ initialize_from_attributes_hash(attributes)
108
+ end
109
+
110
+ def self.search_class_name
111
+ "Item"
112
+ end
113
+
114
+ end
115
+ end
116
+ end
@@ -15,10 +15,14 @@ module NetSuite
15
15
  #
16
16
  # <listAcct:matrixOptionList>
17
17
  # <listAcct:matrixOption internalId="45" scriptId="custitem13">
18
- # <platformCore:value internalId="4" typeId="28"/>
18
+ # <platformCore:value internalId="4" typeId="28">
19
+ # <platformCore:name>foo</platformCore:name>
20
+ # </platformCore:value>
19
21
  # </listAcct:matrixOption>
20
22
  # <listAcct:matrixOption internalId="46" scriptId="custitem14">
21
- # <platformCore:value internalId="1" typeId="29"/>
23
+ # <platformCore:value internalId="1" typeId="29">
24
+ # <platformCore:name>bar</platformCore:name>
25
+ # </platformCore:value>
22
26
  # </listAcct:matrixOption>
23
27
  # </listAcct:matrixOptionList>
24
28
  #
@@ -27,13 +31,17 @@ module NetSuite
27
31
  when Hash
28
32
  options << OpenStruct.new(
29
33
  type_id: attributes[:matrix_option][:value][:'@type_id'],
30
- value_id: attributes[:matrix_option][:value][:'@internal_id']
34
+ value_id: attributes[:matrix_option][:value][:'@internal_id'],
35
+ script_id: attributes[:matrix_option][:@script_id],
36
+ name: attributes[:matrix_option][:value][:name]
31
37
  )
32
38
  when Array
33
39
  attributes[:matrix_option].each do |option|
34
40
  options << OpenStruct.new(
35
41
  type_id: option[:value][:'@type_id'],
36
- value_id: option[:value][:'@internal_id']
42
+ value_id: option[:value][:'@internal_id'],
43
+ script_id: option[:@script_id],
44
+ name: option[:value][:name]
37
45
  )
38
46
  end
39
47
  end
@@ -0,0 +1,30 @@
1
+ module NetSuite
2
+ module Records
3
+ class Message
4
+ include Support::Fields
5
+ include Support::RecordRefs
6
+ include Support::Records
7
+ include Support::Actions
8
+ include Namespaces::CommGeneral
9
+
10
+ actions :get, :add, :delete, :search
11
+
12
+ fields :bcc, :cc, :compress_attachments, :date_time, :emailed, :incoming,
13
+ :message, :record_name, :record_type_name, :subject
14
+
15
+ read_only_fields :last_modified_date, :message_date
16
+
17
+ record_refs :activity, :author, :recipient, :transaction
18
+
19
+ attr_reader :internal_id
20
+ attr_accessor :external_id
21
+
22
+ def initialize(attributes_or_record = {})
23
+ @internal_id = attributes_or_record.delete(:internal_id) || attributes_or_record.delete(:@internal_id)
24
+ @external_id = attributes_or_record.delete(:external_id) || attributes_or_record.delete(:@external_id)
25
+ initialize_from_attributes_hash(attributes_or_record)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -10,7 +10,7 @@ module NetSuite
10
10
  actions :get, :get_list, :add, :delete, :search, :update, :upsert
11
11
 
12
12
  fields :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :country_of_manufacture,
13
- :created_date, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap,
13
+ :created_date, :direct_revenue_posting, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap,
14
14
  :featured_description, :handling_cost, :handling_cost_units, :include_children, :is_donation_item, :is_fulfillable,
15
15
  :is_gco_compliant, :is_inactive, :is_online, :is_taxable, :item_id, :last_modified_date, :manufacturer,
16
16
  :manufacturer_addr1, :manufacturer_city, :manufacturer_state, :manufacturer_tariff, :manufacturer_tax_id,
@@ -52,11 +52,11 @@ module NetSuite
52
52
  :units_type, :sales_tax_code, :sale_unit, :tax_schedule, :parent
53
53
 
54
54
  field :custom_field_list, CustomFieldList
55
- # :pricing_matrix,
55
+ field :pricing_matrix, PricingMatrix
56
56
  # :translations_list,
57
57
  # :matrix_option_list,
58
58
  # :item_options_list
59
- # :subsidiary_list,
59
+ field :subsidiary_list, RecordRefList
60
60
 
61
61
  def initialize(attributes = {})
62
62
  @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
@@ -0,0 +1,26 @@
1
+ module NetSuite
2
+ module Records
3
+ class SupportCaseType
4
+ include Support::Fields
5
+ include Support::RecordRefs
6
+ include Support::Records
7
+ include Support::Actions
8
+ include Namespaces::ListSupport
9
+
10
+ actions :get
11
+
12
+ fields :description, :is_inactive, :name
13
+
14
+ record_refs :insert_before
15
+
16
+ attr_reader :internal_id
17
+ attr_accessor :external_id
18
+
19
+ def initialize(attributes = {})
20
+ @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
21
+ @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
22
+ initialize_from_attributes_hash(attributes)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -7,8 +7,8 @@ module NetSuite
7
7
  include Support::Actions
8
8
  include Namespaces::ListAcct
9
9
 
10
- # NOTE `get_all` is not available in recent API versions ~2017_2
11
- # `search` is only available in recent API versions
10
+ # NOTE `get_all` is not available API > 2017_1
11
+ # `search` is available API > 2016_2
12
12
  actions :get, :get_list, :add, :initialize, :delete, :update, :upsert, :search, :get_all
13
13
 
14
14
  fields :city, :county, :description, :include_children, :is_default, :is_inactive,
@@ -29,8 +29,19 @@ module NetSuite
29
29
  if @total_records > 0
30
30
  if response.body.has_key?(:record_list)
31
31
  # basic search results
32
- record_list = response.body[:record_list][:record]
33
- record_list = [record_list] unless record_list.is_a?(Array)
32
+
33
+ # `recordList` node can contain several nested `record` nodes, only one node or be empty
34
+ # so we have to handle all these cases:
35
+ # * { record_list: nil }
36
+ # * { record_list: { record: => {...} } }
37
+ # * { record_list: { record: => [{...}, {...}, ...] } }
38
+ record_list = if response.body[:record_list].nil?
39
+ []
40
+ elsif response.body[:record_list][:record].is_a?(Array)
41
+ response.body[:record_list][:record]
42
+ else
43
+ [response.body[:record_list][:record]]
44
+ end
34
45
 
35
46
  record_list.each do |record|
36
47
  results << result_class.new(record)
@@ -115,6 +115,7 @@ module NetSuite
115
115
  # https://github.com/stripe/stripe-netsuite/issues/815
116
116
  if !e.message.include?("Only one request may be made against a session at a time") &&
117
117
  !e.message.include?('java.util.ConcurrentModificationException') &&
118
+ !e.message.include?('java.lang.NullPointerException') &&
118
119
  !e.message.include?('java.lang.IllegalStateException') &&
119
120
  !e.message.include?('java.lang.reflect.InvocationTargetException') &&
120
121
  !e.message.include?('com.netledger.common.exceptions.NLDatabaseOfflineException') &&
@@ -173,6 +174,7 @@ module NetSuite
173
174
  ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::KitItem, ns_item_internal_id, opts)
174
175
  ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::SerializedInventoryItem, ns_item_internal_id, opts)
175
176
  ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::LotNumberedAssemblyItem, ns_item_internal_id, opts)
177
+ ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::LotNumberedInventoryItem, ns_item_internal_id, opts)
176
178
 
177
179
  if ns_item.nil?
178
180
  fail NetSuite::RecordNotFound, "item with ID #{ns_item_internal_id} not found"
@@ -277,16 +279,25 @@ module NetSuite
277
279
  # NetSuite requires that the time be passed to the API with the PDT TZ offset
278
280
  # of the time passed in (i.e. not the current TZ offset of PDT)
279
281
 
280
- offset = Rational(-7, 24)
281
-
282
282
  if defined?(TZInfo)
283
- time = TZInfo::Timezone.get("America/Los_Angeles").utc_to_local(time)
284
- offset = time.offset
283
+ # if no version is defined, less than 2.0
284
+ # https://github.com/tzinfo/tzinfo/blob/master/CHANGES.md#added
285
+ if !defined?(TZInfo::VERSION)
286
+ # https://stackoverflow.com/questions/2927111/ruby-get-time-in-given-timezone
287
+ offset = TZInfo::Timezone.get("America/Los_Angeles").period_for_utc(time).utc_total_offset_rational
288
+ time = time.new_offset(offset)
289
+ else
290
+ time = TZInfo::Timezone.get("America/Los_Angeles").utc_to_local(time)
291
+ offset = time.offset
292
+ end
285
293
  else
294
+ # if tzinfo is not installed, let's give it our best guess: -7
295
+ offset = Rational(-7, 24)
286
296
  time = time.new_offset("-07:00")
287
297
  end
288
298
 
289
- (time + (offset * -1)).iso8601
299
+ time = (time + (offset * -1))
300
+ time.iso8601
290
301
  end
291
302
 
292
303
  end
@@ -1,3 +1,3 @@
1
1
  module NetSuite
2
- VERSION = '0.8.4'
2
+ VERSION = '0.8.5'
3
3
  end
@@ -17,5 +17,5 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_dependency 'savon', '>= 2.3.0'
19
19
 
20
- gem.add_development_dependency 'rspec', '~> 3.1.0'
20
+ gem.add_development_dependency 'rspec', '~> 3.8.0'
21
21
  end
@@ -371,4 +371,22 @@ describe NetSuite::Configuration do
371
371
  end
372
372
  end
373
373
 
374
+ describe 'timeouts' do
375
+ it 'has defaults' do
376
+ expect(config.read_timeout).to eql(60)
377
+ expect(config.open_timeout).to be_nil
378
+ end
379
+
380
+ it 'sets timeouts' do
381
+ config.read_timeout = 100
382
+ config.open_timeout = 60
383
+
384
+ expect(config.read_timeout).to eql(100)
385
+ expect(config.open_timeout).to eql(60)
386
+
387
+ # ensure no exception is raised
388
+ config.connection
389
+ end
390
+ end
391
+
374
392
  end
@@ -25,6 +25,7 @@ describe 'basic records' do
25
25
  NetSuite::Records::CustomerDeposit,
26
26
  NetSuite::Records::NonInventoryPurchaseItem,
27
27
  NetSuite::Records::NonInventoryResaleItem,
28
+ NetSuite::Records::LotNumberedInventoryItem,
28
29
  NetSuite::Records::TaxGroup,
29
30
  NetSuite::Records::Folder,
30
31
  NetSuite::Records::CustomerCategory,
@@ -5,20 +5,30 @@ module NetSuite
5
5
  module Records
6
6
  describe MatrixOptionList do
7
7
  it "deals with hash properly" do
8
- hash = {:value=>{:@internal_id=>"1", :@type_id=>"36"}}
8
+ hash = {:value=>{:@internal_id=>"1", :@type_id=>"36", :name=>"some value"}, :@script_id=>'cust_field_1'}
9
9
 
10
10
  list = described_class.new({ matrix_option: hash })
11
- expect(list.options.first.value_id).to eq "1"
11
+ option = list.options.first
12
+ expect(option.value_id).to eq "1"
13
+ expect(option.type_id).to eq "36"
14
+ expect(option.name).to eq "some value"
15
+ expect(option.script_id).to eq "cust_field_1"
12
16
  end
13
17
 
14
18
  it "deals with arrays properly" do
15
19
  array = [
16
- {:value=>{:@internal_id=>"2", :@type_id=>"28"}},
17
- {:value=>{:@internal_id=>"1", :@type_id=>"29"}}
20
+ {:value=>{:@internal_id=>"2", :@type_id=>"28", :name=>"some value 28"}, :@script_id=>'cust_field_28'},
21
+ {:value=>{:@internal_id=>"1", :@type_id=>"29", :name=>"some value 29"}, :@script_id=>'cust_field_29'}
18
22
  ]
19
23
 
20
24
  list = described_class.new({ matrix_option: array })
21
- expect(list.options.first.value_id).to eq "2"
25
+ expect(list.options.count).to eq 2
26
+
27
+ option = list.options.first
28
+ expect(option.value_id).to eq "2"
29
+ expect(option.type_id).to eq "28"
30
+ expect(option.name).to eq "some value 28"
31
+ expect(option.script_id).to eq "cust_field_28"
22
32
  end
23
33
  end
24
34
  end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe NetSuite::Records::Message do
4
+ let(:message) { NetSuite::Records::Message.new }
5
+
6
+ it 'has all the right fields' do
7
+ [
8
+ :bcc, :cc, :compress_attachments, :date_time, :emailed,
9
+ :incoming, :message, :record_name, :record_type_name, :subject,
10
+ :last_modified_date, :message_date
11
+ ].each do |field|
12
+ expect(message).to have_field(field)
13
+ end
14
+ end
15
+
16
+ it 'has the right record_refs' do
17
+ [
18
+ :activity, :author, :recipient, :transaction
19
+ ].each do |record_ref|
20
+ expect(message).to have_record_ref(record_ref)
21
+ end
22
+ end
23
+
24
+ describe '.get' do
25
+ context 'when the response is successful' do
26
+ let(:response) { NetSuite::Response.new(:success => true, :body => {message: 'message text'})}
27
+
28
+ it 'returns a Message instance populated with data from the response object' do
29
+ expect(NetSuite::Actions::Get).to receive(:call).with([NetSuite::Records::Message, :external_id => 1], {}).and_return(response)
30
+
31
+ message = NetSuite::Records::Message.get(:external_id => 1)
32
+ expect(message).to be_kind_of(NetSuite::Records::Message)
33
+ expect(message.message).to eq('message text')
34
+ end
35
+ end
36
+
37
+ context 'when response is unsuccessful' do
38
+ let(:response) { NetSuite::Response.new(:success => false, :body => {}) }
39
+ it 'raises a RecordNotFound exception' do
40
+ expect(NetSuite::Actions::Get).to receive(:call).with([NetSuite::Records::Message, :external_id => 1], {}).and_return(response)
41
+ expect {
42
+ NetSuite::Records::Message.get(:external_id => 1)
43
+ }.to raise_error(NetSuite::RecordNotFound,
44
+ /NetSuite::Records::Message with OPTIONS=(.*) could not be found/)
45
+ end
46
+ end
47
+ end
48
+
49
+ end
@@ -6,7 +6,7 @@ describe NetSuite::Records::NonInventorySaleItem do
6
6
  it 'has the right fields' do
7
7
  [
8
8
  :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :country_of_manufacture, :created_date,
9
- :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap,
9
+ :direct_revenue_posting, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap,
10
10
  :featured_description, :handling_cost, :handling_cost_units, :include_children, :is_donation_item, :is_fulfillable,
11
11
  :is_gco_compliant, :is_inactive, :is_online, :is_taxable, :item_id, :last_modified_date, :manufacturer, :manufacturer_addr1,
12
12
  :manufacturer_city, :manufacturer_state, :manufacturer_tariff, :manufacturer_tax_id, :manufacturer_zip, :matrix_option_list,
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe NetSuite::Records::SupportCaseType do
4
+ let(:support_case_type) { NetSuite::Records::SupportCaseType.new }
5
+
6
+ it 'has all the right fields' do
7
+ [
8
+ :description, :is_inactive, :name
9
+ ].each do |field|
10
+ expect(support_case_type).to have_field(field)
11
+ end
12
+ end
13
+
14
+ it 'has the right record_refs' do
15
+ [
16
+ :insert_before
17
+ ].each do |record_ref|
18
+ expect(support_case_type).to have_record_ref(record_ref)
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe NetSuite::Support::SearchResult do
4
+ describe '#results' do
5
+ context 'empty page' do
6
+ it 'returns empty array' do
7
+ response_body = {
8
+ :status => {:@is_success=>"true"},
9
+ :total_records => "242258",
10
+ :page_size => "10",
11
+ :total_pages => "24226",
12
+ :page_index => "99",
13
+ :search_id => "WEBSERVICES_4132604_SB1_051620191060155623420663266_336cbf12",
14
+ :record_list => nil,
15
+ :"@xmlns:platform_core" => "urn:core_2016_2.platform.webservices.netsuite.com"
16
+ }
17
+ response = NetSuite::Response.new(body: response_body)
18
+
19
+ results = described_class.new(response, NetSuite::Actions::Search, {}).results
20
+ expect(results).to eq []
21
+ end
22
+ end
23
+ end
24
+ end
@@ -3,24 +3,29 @@ require 'spec_helper'
3
3
  describe NetSuite::Utilities do
4
4
  describe 'time utilities' do
5
5
  it '#normalize_time_to_netsuite_date' do
6
- stamp = DateTime.parse('Wed, 27 Jul 2016 00:00:00 -0000')
7
- formatted_date = NetSuite::Utilities.normalize_time_to_netsuite_date(stamp.to_time.to_i)
8
- expect(formatted_date).to eq('2016-07-27T00:00:00-07:00')
6
+ ['Etc/UTC', 'America/Los_Angeles', 'America/Denver'].each do |zone|
7
+ ENV['TZ'] = zone
8
+ puts "In zone: #{zone}"
9
9
 
10
- no_dst_stamp = DateTime.parse('Sun, November 6 2017 00:00:00 -0000')
11
- formatted_date = NetSuite::Utilities.normalize_time_to_netsuite_date(no_dst_stamp.to_time.to_i)
12
- expect(formatted_date).to eq('2017-11-06T00:00:00-08:00')
10
+ stamp = DateTime.parse('Wed, 27 Jul 2016 00:00:00 -0000')
11
+ formatted_date = NetSuite::Utilities.normalize_time_to_netsuite_date(stamp.to_time.to_i)
12
+ expect(formatted_date).to eq('2016-07-27T00:00:00-07:00')
13
13
 
14
- no_dst_stamp_with_time = DateTime.parse('Sun, November 6 2017 12:11:10 -0000')
15
- formatted_date = NetSuite::Utilities.normalize_time_to_netsuite_date(no_dst_stamp_with_time.to_time.to_i)
16
- expect(formatted_date).to eq('2017-11-06T00:00:00-08:00')
14
+ no_dst_stamp = DateTime.parse('Sun, November 6 2017 00:00:00 -0000')
15
+ formatted_date = NetSuite::Utilities.normalize_time_to_netsuite_date(no_dst_stamp.to_time.to_i)
16
+ expect(formatted_date).to eq('2017-11-06T00:00:00-08:00')
17
+
18
+ no_dst_stamp_with_time = DateTime.parse('Sun, November 6 2017 12:11:10 -0000')
19
+ formatted_date = NetSuite::Utilities.normalize_time_to_netsuite_date(no_dst_stamp_with_time.to_time.to_i)
20
+ expect(formatted_date).to eq('2017-11-06T00:00:00-08:00')
21
+ end
17
22
  end
18
23
  end
19
24
 
20
25
  it "#netsuite_data_center_urls" do
21
26
  domains = NetSuite::Utilities.netsuite_data_center_urls('TSTDRV1576318')
22
- expect(domains[:webservices_domain]).to eq('https://webservices.netsuite.com')
23
- expect(domains[:system_domain]).to eq('https://system.netsuite.com')
27
+ expect(domains[:webservices_domain]).to eq('https://tstdrv1576318.suitetalk.api.netsuite.com')
28
+ expect(domains[:system_domain]).to eq('https://tstdrv1576318.app.netsuite.com')
24
29
 
25
30
  # ensure domains returned don't change when sandbox is enabled
26
31
  NetSuite.configure do
@@ -29,8 +34,8 @@ describe NetSuite::Utilities do
29
34
  end
30
35
 
31
36
  domains = NetSuite::Utilities.netsuite_data_center_urls('TSTDRV1576318')
32
- expect(domains[:webservices_domain]).to eq('https://webservices.netsuite.com')
33
- expect(domains[:system_domain]).to eq('https://system.netsuite.com')
37
+ expect(domains[:webservices_domain]).to eq('https://tstdrv1576318.suitetalk.api.netsuite.com')
38
+ expect(domains[:system_domain]).to eq('https://tstdrv1576318.app.netsuite.com')
34
39
 
35
40
  NetSuite.configure do
36
41
  reset!
@@ -38,8 +43,8 @@ describe NetSuite::Utilities do
38
43
  end
39
44
 
40
45
  domains = NetSuite::Utilities.netsuite_data_center_urls('TSTDRV1576318')
41
- expect(domains[:webservices_domain]).to eq('https://webservices.netsuite.com')
42
- expect(domains[:system_domain]).to eq('https://system.netsuite.com')
46
+ expect(domains[:webservices_domain]).to eq('https://tstdrv1576318.suitetalk.api.netsuite.com')
47
+ expect(domains[:system_domain]).to eq('https://tstdrv1576318.app.netsuite.com')
43
48
 
44
49
  domains = NetSuite::Utilities.netsuite_data_center_urls('4810331')
45
50
  expect(domains[:webservices_domain]).to eq('https://4810331.suitetalk.api.netsuite.com')
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.8.4
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Moran
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-03-08 00:00:00.000000000 Z
12
+ date: 2019-07-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: savon
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 3.1.0
34
+ version: 3.8.0
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 3.1.0
41
+ version: 3.8.0
42
42
  description: NetSuite SuiteTalk API Wrapper
43
43
  email:
44
44
  - ryan.moran@gmail.com
@@ -234,8 +234,10 @@ files:
234
234
  - lib/netsuite/records/location.rb
235
235
  - lib/netsuite/records/locations_list.rb
236
236
  - lib/netsuite/records/lot_numbered_assembly_item.rb
237
+ - lib/netsuite/records/lot_numbered_inventory_item.rb
237
238
  - lib/netsuite/records/matrix_option_list.rb
238
239
  - lib/netsuite/records/member_list.rb
240
+ - lib/netsuite/records/message.rb
239
241
  - lib/netsuite/records/non_inventory_purchase_item.rb
240
242
  - lib/netsuite/records/non_inventory_resale_item.rb
241
243
  - lib/netsuite/records/non_inventory_sale_item.rb
@@ -289,6 +291,7 @@ files:
289
291
  - lib/netsuite/records/subsidiary.rb
290
292
  - lib/netsuite/records/subtotal_item.rb
291
293
  - lib/netsuite/records/support_case.rb
294
+ - lib/netsuite/records/support_case_type.rb
292
295
  - lib/netsuite/records/task.rb
293
296
  - lib/netsuite/records/tax_group.rb
294
297
  - lib/netsuite/records/tax_type.rb
@@ -436,6 +439,7 @@ files:
436
439
  - spec/netsuite/records/kit_item_spec.rb
437
440
  - spec/netsuite/records/location_spec.rb
438
441
  - spec/netsuite/records/matrix_option_list_spec.rb
442
+ - spec/netsuite/records/message_spec.rb
439
443
  - spec/netsuite/records/non_inventory_sale_item_spec.rb
440
444
  - spec/netsuite/records/note_spec.rb
441
445
  - spec/netsuite/records/note_type_spec.rb
@@ -458,6 +462,7 @@ files:
458
462
  - spec/netsuite/records/site_category_spec.rb
459
463
  - spec/netsuite/records/subsidiary_spec.rb
460
464
  - spec/netsuite/records/support_case_spec.rb
465
+ - spec/netsuite/records/support_case_type_spec.rb
461
466
  - spec/netsuite/records/tax_type_spec.rb
462
467
  - spec/netsuite/records/term_spec.rb
463
468
  - spec/netsuite/records/transaction_body_custom_field_spec.rb
@@ -485,6 +490,7 @@ files:
485
490
  - spec/netsuite/support/record_refs_spec.rb
486
491
  - spec/netsuite/support/records_spec.rb
487
492
  - spec/netsuite/support/requests_spec.rb
493
+ - spec/netsuite/support/search_result_spec.rb
488
494
  - spec/netsuite/support/sublist_spec.rb
489
495
  - spec/netsuite/utilities/data_center_spec.rb
490
496
  - spec/netsuite/utilities/request_spec.rb
@@ -646,6 +652,7 @@ test_files:
646
652
  - spec/netsuite/records/kit_item_spec.rb
647
653
  - spec/netsuite/records/location_spec.rb
648
654
  - spec/netsuite/records/matrix_option_list_spec.rb
655
+ - spec/netsuite/records/message_spec.rb
649
656
  - spec/netsuite/records/non_inventory_sale_item_spec.rb
650
657
  - spec/netsuite/records/note_spec.rb
651
658
  - spec/netsuite/records/note_type_spec.rb
@@ -668,6 +675,7 @@ test_files:
668
675
  - spec/netsuite/records/site_category_spec.rb
669
676
  - spec/netsuite/records/subsidiary_spec.rb
670
677
  - spec/netsuite/records/support_case_spec.rb
678
+ - spec/netsuite/records/support_case_type_spec.rb
671
679
  - spec/netsuite/records/tax_type_spec.rb
672
680
  - spec/netsuite/records/term_spec.rb
673
681
  - spec/netsuite/records/transaction_body_custom_field_spec.rb
@@ -695,6 +703,7 @@ test_files:
695
703
  - spec/netsuite/support/record_refs_spec.rb
696
704
  - spec/netsuite/support/records_spec.rb
697
705
  - spec/netsuite/support/requests_spec.rb
706
+ - spec/netsuite/support/search_result_spec.rb
698
707
  - spec/netsuite/support/sublist_spec.rb
699
708
  - spec/netsuite/utilities/data_center_spec.rb
700
709
  - spec/netsuite/utilities/request_spec.rb