netsuite 0.8.2 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/Gemfile +7 -2
  5. data/README.md +107 -32
  6. data/circle.yml +33 -13
  7. data/lib/netsuite.rb +36 -19
  8. data/lib/netsuite/actions/login.rb +20 -1
  9. data/lib/netsuite/actions/search.rb +1 -6
  10. data/lib/netsuite/actions/update.rb +6 -2
  11. data/lib/netsuite/actions/update_list.rb +109 -0
  12. data/lib/netsuite/actions/upsert.rb +2 -0
  13. data/lib/netsuite/configuration.rb +21 -4
  14. data/lib/netsuite/errors.rb +1 -0
  15. data/lib/netsuite/records/assembly_build.rb +4 -1
  16. data/lib/netsuite/records/assembly_item.rb +1 -0
  17. data/lib/netsuite/records/assembly_unbuild.rb +3 -0
  18. data/lib/netsuite/records/bin_number.rb +18 -0
  19. data/lib/netsuite/records/bin_number_list.rb +1 -20
  20. data/lib/netsuite/records/bin_transfer.rb +38 -0
  21. data/lib/netsuite/records/bin_transfer_inventory.rb +20 -0
  22. data/lib/netsuite/records/bin_transfer_inventory_list.rb +10 -0
  23. data/lib/netsuite/records/cash_refund_item.rb +1 -1
  24. data/lib/netsuite/records/classification.rb +5 -2
  25. data/lib/netsuite/records/custom_field_list.rb +10 -2
  26. data/lib/netsuite/records/custom_record.rb +3 -3
  27. data/lib/netsuite/records/custom_record_ref.rb +1 -0
  28. data/lib/netsuite/records/customer.rb +5 -4
  29. data/lib/netsuite/records/customer_credit_cards.rb +36 -0
  30. data/lib/netsuite/records/customer_credit_cards_list.rb +10 -0
  31. data/lib/netsuite/records/customer_deposit.rb +5 -2
  32. data/lib/netsuite/records/customer_payment.rb +1 -0
  33. data/lib/netsuite/records/customer_sales_team.rb +24 -0
  34. data/lib/netsuite/records/customer_sales_team_list.rb +9 -0
  35. data/lib/netsuite/records/customer_status.rb +29 -0
  36. data/lib/netsuite/records/customer_subscription.rb +18 -0
  37. data/lib/netsuite/records/customer_subscriptions_list.rb +10 -0
  38. data/lib/netsuite/records/employee.rb +1 -1
  39. data/lib/netsuite/records/entity_custom_field.rb +53 -0
  40. data/lib/netsuite/records/estimate.rb +42 -0
  41. data/lib/netsuite/records/estimate_item.rb +40 -0
  42. data/lib/netsuite/records/estimate_item_list.rb +11 -0
  43. data/lib/netsuite/records/inbound_shipment.rb +33 -0
  44. data/lib/netsuite/records/inbound_shipment_item.rb +39 -0
  45. data/lib/netsuite/records/inbound_shipment_item_list.rb +11 -0
  46. data/lib/netsuite/records/inter_company_journal_entry.rb +48 -0
  47. data/lib/netsuite/records/inter_company_journal_entry_line.rb +28 -0
  48. data/lib/netsuite/records/inter_company_journal_entry_line_list.rb +14 -0
  49. data/lib/netsuite/records/inventory_item.rb +1 -1
  50. data/lib/netsuite/records/invoice.rb +1 -1
  51. data/lib/netsuite/records/item_fulfillment.rb +1 -1
  52. data/lib/netsuite/records/lot_numbered_inventory_item.rb +116 -0
  53. data/lib/netsuite/records/matrix_option_list.rb +12 -4
  54. data/lib/netsuite/records/message.rb +30 -0
  55. data/lib/netsuite/records/non_inventory_resale_item.rb +3 -2
  56. data/lib/netsuite/records/non_inventory_sale_item.rb +1 -1
  57. data/lib/netsuite/records/other_charge_sale_item.rb +2 -2
  58. data/lib/netsuite/records/partner.rb +1 -1
  59. data/lib/netsuite/records/price.rb +17 -0
  60. data/lib/netsuite/records/price_level.rb +26 -0
  61. data/lib/netsuite/records/price_list.rb +9 -0
  62. data/lib/netsuite/records/pricing.rb +20 -0
  63. data/lib/netsuite/records/pricing_matrix.rb +2 -2
  64. data/lib/netsuite/records/promotions.rb +26 -0
  65. data/lib/netsuite/records/promotions_list.rb +9 -0
  66. data/lib/netsuite/records/return_authorization_item.rb +1 -1
  67. data/lib/netsuite/records/sales_order.rb +1 -0
  68. data/lib/netsuite/records/sales_order_item.rb +12 -5
  69. data/lib/netsuite/records/sales_role.rb +26 -0
  70. data/lib/netsuite/records/sales_tax_item.rb +3 -1
  71. data/lib/netsuite/records/serialized_assembly_item.rb +239 -0
  72. data/lib/netsuite/records/service_resale_item.rb +1 -1
  73. data/lib/netsuite/records/service_sale_item.rb +1 -1
  74. data/lib/netsuite/records/support_case.rb +1 -1
  75. data/lib/netsuite/records/support_case_type.rb +26 -0
  76. data/lib/netsuite/records/tax_group.rb +2 -2
  77. data/lib/netsuite/records/transaction_body_custom_field.rb +61 -0
  78. data/lib/netsuite/records/transaction_column_custom_field.rb +59 -0
  79. data/lib/netsuite/records/vendor_credit.rb +2 -0
  80. data/lib/netsuite/records/work_order.rb +8 -0
  81. data/lib/netsuite/support/actions.rb +2 -0
  82. data/lib/netsuite/support/country.rb +27 -15
  83. data/lib/netsuite/support/search_result.rb +20 -5
  84. data/lib/netsuite/utilities.rb +83 -21
  85. data/lib/netsuite/version.rb +1 -1
  86. data/netsuite.gemspec +4 -3
  87. data/spec/netsuite/actions/login_spec.rb +23 -0
  88. data/spec/netsuite/actions/update_list_spec.rb +107 -0
  89. data/spec/netsuite/actions/update_spec.rb +42 -0
  90. data/spec/netsuite/configuration_spec.rb +79 -6
  91. data/spec/netsuite/records/address_spec.rb +10 -0
  92. data/spec/netsuite/records/basic_record_spec.rb +11 -1
  93. data/spec/netsuite/records/bin_number_spec.rb +23 -0
  94. data/spec/netsuite/records/classification_spec.rb +10 -1
  95. data/spec/netsuite/records/custom_field_list_spec.rb +39 -4
  96. data/spec/netsuite/records/custom_record_spec.rb +1 -1
  97. data/spec/netsuite/records/customer_credit_cards_list_spec.rb +23 -0
  98. data/spec/netsuite/records/customer_sales_team_list_spec.rb +41 -0
  99. data/spec/netsuite/records/customer_spec.rb +44 -2
  100. data/spec/netsuite/records/customer_subscription_spec.rb +41 -0
  101. data/spec/netsuite/records/customer_subscriptions_list_spec.rb +19 -0
  102. data/spec/netsuite/records/employee_spec.rb +2 -2
  103. data/spec/netsuite/records/entity_custom_field_spec.rb +34 -0
  104. data/spec/netsuite/records/estimate_item_list_spec.rb +26 -0
  105. data/spec/netsuite/records/estimate_item_spec.rb +40 -0
  106. data/spec/netsuite/records/estimate_spec.rb +216 -0
  107. data/spec/netsuite/records/inter_company_journal_entry_line_list_spec.rb +26 -0
  108. data/spec/netsuite/records/inter_company_journal_entry_line_spec.rb +60 -0
  109. data/spec/netsuite/records/inter_company_journal_entry_spec.rb +156 -0
  110. data/spec/netsuite/records/inventory_item_spec.rb +57 -0
  111. data/spec/netsuite/records/matrix_option_list_spec.rb +15 -5
  112. data/spec/netsuite/records/message_spec.rb +49 -0
  113. data/spec/netsuite/records/non_inventory_resale_item_spec.rb +165 -0
  114. data/spec/netsuite/records/non_inventory_sale_item_spec.rb +1 -1
  115. data/spec/netsuite/records/partner_spec.rb +141 -0
  116. data/spec/netsuite/records/price_level_spec.rb +16 -0
  117. data/spec/netsuite/records/pricing_matrix_spec.rb +15 -13
  118. data/spec/netsuite/records/return_authorization_item_spec.rb +1 -1
  119. data/spec/netsuite/records/sales_order_item_spec.rb +11 -5
  120. data/spec/netsuite/records/service_resale_item_spec.rb +134 -0
  121. data/spec/netsuite/records/support_case_type_spec.rb +22 -0
  122. data/spec/netsuite/records/transaction_body_custom_field_spec.rb +32 -0
  123. data/spec/netsuite/records/transaction_column_custom_field_spec.rb +32 -0
  124. data/spec/netsuite/records/vendor_credit_spec.rb +29 -0
  125. data/spec/netsuite/support/search_result_spec.rb +24 -0
  126. data/spec/netsuite/utilities_spec.rb +44 -6
  127. data/spec/spec_helper.rb +5 -4
  128. data/spec/support/fixtures/update_list/update_list_items.xml +22 -0
  129. data/spec/support/fixtures/update_list/update_list_one_item.xml +18 -0
  130. data/spec/support/fixtures/update_list/update_list_with_errors.xml +32 -0
  131. metadata +101 -8
@@ -7,8 +7,8 @@ module NetSuite
7
7
  include Support::Actions
8
8
  include Namespaces::ListAcct
9
9
 
10
- # NOTE search not available on TaxGroup!
11
-
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,
@@ -0,0 +1,61 @@
1
+ module NetSuite
2
+ module Records
3
+ class TransactionBodyCustomField
4
+ include Support::Fields
5
+ include Support::RecordRefs
6
+ include Support::Records
7
+ include Support::Actions
8
+ include Namespaces::SetupCustom
9
+
10
+ actions :get, :get_list, :add, :delete, :update, :upsert, :upsert_list
11
+
12
+ # http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2017_1/schema/record/transactionbodycustomfield.html
13
+ fields(
14
+ :label,
15
+ :store_value,
16
+ :display_type,
17
+ :is_mandatory,
18
+ :default_checked,
19
+ :is_formula,
20
+ :body_assembly_build,
21
+ :body_bom,
22
+ :body_b_tegata,
23
+ :body_customer_payment,
24
+ :body_deposit,
25
+ :body_expense_report,
26
+ :body_inventory_adjustment,
27
+ :body_item_fulfillment,
28
+ :body_item_fulfillment_order,
29
+ :body_item__receipt,
30
+ :body_item__receipt_order,
31
+ :body_journal,
32
+ :body_opportunity,
33
+ :body_other_transaction,
34
+ :body_picking_ticket,
35
+ :body_print_flag,
36
+ :body_print_packing_slip,
37
+ :body_print_statement,
38
+ :body_purchase,
39
+ :body_sale,
40
+ :body_store,
41
+ :body_transfer_order,
42
+ :body_vendor_payment,
43
+ :access_level,
44
+ :search_level,
45
+ :field_type,
46
+ :script_id
47
+ )
48
+
49
+ record_refs :owner
50
+
51
+ attr_reader :internal_id
52
+ attr_accessor :external_id
53
+
54
+ def initialize(attributes = {})
55
+ @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
56
+ @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
57
+ initialize_from_attributes_hash(attributes)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,59 @@
1
+ module NetSuite
2
+ module Records
3
+ class TransactionColumnCustomField
4
+ include Support::Fields
5
+ include Support::RecordRefs
6
+ include Support::Records
7
+ include Support::Actions
8
+ include Namespaces::SetupCustom
9
+
10
+ actions :get, :get_list, :add, :delete, :update, :upsert, :upsert_list
11
+
12
+ # http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2017_1/schema/record/transactioncolumncustomfield.html
13
+ fields(
14
+ :label,
15
+ :store_value,
16
+ :display_type,
17
+ :is_mandatory,
18
+ :default_checked,
19
+ :is_formula,
20
+ :col_expense,
21
+ :col_purchase,
22
+ :col_sale,
23
+ :col_opportunity,
24
+ :col_store,
25
+ :col_store_hidden,
26
+ :col_journal,
27
+ :col_expense_report,
28
+ :col_time,
29
+ :col_transfer_order,
30
+ :col_item_receipt,
31
+ :col_item_receipt_order,
32
+ :col_item_fulfillment,
33
+ :col_item_fulfillment_order,
34
+ :col_print_flag,
35
+ :col_picking_ticket,
36
+ :col_packing_slip,
37
+ :col_return_form,
38
+ :col_store_with_groups,
39
+ :col_group_on_invoices,
40
+ :col_kit_item,
41
+ :access_level,
42
+ :search_level,
43
+ :field_type,
44
+ :script_id
45
+ )
46
+
47
+ record_refs :owner
48
+
49
+ attr_reader :internal_id
50
+ attr_accessor :external_id
51
+
52
+ def initialize(attributes = {})
53
+ @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
54
+ @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
55
+ initialize_from_attributes_hash(attributes)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -33,9 +33,11 @@ module NetSuite
33
33
  field :custom_field_list, CustomFieldList
34
34
 
35
35
  attr_reader :internal_id
36
+ attr_accessor :external_id
36
37
 
37
38
  def initialize(attributes = {})
38
39
  @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
40
+ @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
39
41
  initialize_from_attributes_hash(attributes)
40
42
  end
41
43
 
@@ -33,6 +33,14 @@ module NetSuite
33
33
  @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
34
34
  initialize_from_attributes_hash(attributes)
35
35
  end
36
+
37
+ def self.search_class_name
38
+ "Transaction"
39
+ end
40
+
41
+ def self.search_class_namespace
42
+ 'tranSales'
43
+ end
36
44
  end
37
45
  end
38
46
  end
@@ -42,6 +42,8 @@ module NetSuite
42
42
  self.send(:include, NetSuite::Actions::DeleteList::Support)
43
43
  when :update
44
44
  self.send(:include, NetSuite::Actions::Update::Support)
45
+ when :update_list
46
+ self.send(:include, NetSuite::Actions::UpdateList::Support)
45
47
  when :initialize
46
48
  self.send(:include, NetSuite::Actions::Initialize::Support)
47
49
  else
@@ -4,6 +4,7 @@ module NetSuite
4
4
 
5
5
  ISO_TO_NETSUITE = {
6
6
  'AF' => '_afghanistan',
7
+ 'AX' => '_alandIslands',
7
8
  'AL' => '_albania',
8
9
  'DZ' => '_algeria',
9
10
  'AS' => '_americanSamoa',
@@ -29,6 +30,7 @@ module NetSuite
29
30
  'BM' => '_bermuda',
30
31
  'BT' => '_bhutan',
31
32
  'BO' => '_bolivia',
33
+ 'BQ' => '_bonaireSaintEustatiusAndSaba',
32
34
  'BA' => '_bosniaAndHerzegovina',
33
35
  'BW' => '_botswana',
34
36
  'BV' => '_bouvetIsland',
@@ -41,9 +43,11 @@ module NetSuite
41
43
  'KH' => '_cambodia',
42
44
  'CM' => '_cameroon',
43
45
  'CA' => '_canada',
44
- 'CV' => '_capVerde',
46
+ 'IC' => '_canaryIslands',
47
+ 'CV' => '_capeVerde',
45
48
  'KY' => '_caymanIslands',
46
49
  'CF' => '_centralAfricanRepublic',
50
+ 'EA' => '_ceutaAndMelilla',
47
51
  'TD' => '_chad',
48
52
  'CL' => '_chile',
49
53
  'CN' => '_china',
@@ -65,7 +69,7 @@ module NetSuite
65
69
  'DJ' => '_djibouti',
66
70
  'DM' => '_dominica',
67
71
  'DO' => '_dominicanRepublic',
68
- 'TP' => '_eastTimor',
72
+ 'TL' => '_eastTimor',
69
73
  'EC' => '_ecuador',
70
74
  'EG' => '_egypt',
71
75
  'SV' => '_elSalvador',
@@ -73,7 +77,7 @@ module NetSuite
73
77
  'ER' => '_eritrea',
74
78
  'EE' => '_estonia',
75
79
  'ET' => '_ethiopia',
76
- 'FK' => '_falklandIslandsMalvina',
80
+ 'FK' => '_falklandIslands',
77
81
  'FO' => '_faroeIslands',
78
82
  'FJ' => '_fiji',
79
83
  'FI' => '_finland',
@@ -121,6 +125,7 @@ module NetSuite
121
125
  'KI' => '_kiribati',
122
126
  'KP' => '_koreaDemocraticPeoplesRepublic',
123
127
  'KR' => '_koreaRepublicOf',
128
+ 'XK' => '_kosovo',
124
129
  'KW' => '_kuwait',
125
130
  'KG' => '_kyrgyzstan',
126
131
  'LA' => '_laoPeoplesDemocraticRepublic',
@@ -128,7 +133,7 @@ module NetSuite
128
133
  'LB' => '_lebanon',
129
134
  'LS' => '_lesotho',
130
135
  'LR' => '_liberia',
131
- 'LY' => '_libyanArabJamahiriya',
136
+ 'LY' => '_libya',
132
137
  'LI' => '_liechtenstein',
133
138
  'LT' => '_lithuania',
134
139
  'LU' => '_luxembourg',
@@ -159,7 +164,6 @@ module NetSuite
159
164
  'NR' => '_nauru',
160
165
  'NP' => '_nepal',
161
166
  'NL' => '_netherlands',
162
- 'AN' => '_netherlandsAntilles',
163
167
  'NC' => '_newCaledonia',
164
168
  'NZ' => '_newZealand',
165
169
  'NI' => '_nicaragua',
@@ -172,7 +176,7 @@ module NetSuite
172
176
  'OM' => '_oman',
173
177
  'PK' => '_pakistan',
174
178
  'PW' => '_palau',
175
- 'PS' => '_palestinianTerritories',
179
+ 'PS' => '_stateOfPalestine',
176
180
  'PA' => '_panama',
177
181
  'PG' => '_papuaNewGuinea',
178
182
  'PY' => '_paraguay',
@@ -185,18 +189,19 @@ module NetSuite
185
189
  'QA' => '_qatar',
186
190
  'RE' => '_reunionIsland',
187
191
  'RO' => '_romania',
188
- 'RS' => '_serbia',
189
192
  'RU' => '_russianFederation',
190
193
  'RW' => '_rwanda',
191
194
  'BL' => '_saintBarthelemy',
195
+ 'SH' => '_saintHelena',
192
196
  'KN' => '_saintKittsAndNevis',
193
197
  'LC' => '_saintLucia',
198
+ 'MF' => '_saintMartin',
194
199
  'VC' => '_saintVincentAndTheGrenadines',
195
200
  'SM' => '_sanMarino',
196
201
  'ST' => '_saoTomeAndPrincipe',
197
202
  'SA' => '_saudiArabia',
198
203
  'SN' => '_senegal',
199
- 'CS' => '_serbia',
204
+ 'RS' => '_serbia',
200
205
  'SC' => '_seychelles',
201
206
  'SL' => '_sierraLeone',
202
207
  'SG' => '_singapore',
@@ -207,9 +212,9 @@ module NetSuite
207
212
  'SO' => '_somalia',
208
213
  'ZA' => '_southAfrica',
209
214
  'GS' => '_southGeorgia',
215
+ 'SS' => '_southSudan',
210
216
  'ES' => '_spain',
211
217
  'LK' => '_sriLanka',
212
- 'SH' => '_stHelena',
213
218
  'PM' => '_stPierreAndMiquelon',
214
219
  'SD' => '_sudan',
215
220
  'SR' => '_suriname',
@@ -234,8 +239,7 @@ module NetSuite
234
239
  'UG' => '_uganda',
235
240
  'UA' => '_ukraine',
236
241
  'AE' => '_unitedArabEmirates',
237
- # NOTE GB country code changed on 2016_1
238
- 'GB' => NetSuite::Configuration.api_version <= "2015_2" ? '_unitedKingdomGB' : '_unitedKingdom',
242
+ 'GB' => '_unitedKingdom',
239
243
  'US' => '_unitedStates',
240
244
  'UY' => '_uruguay',
241
245
  'UM' => '_uSMinorOutlyingIslands',
@@ -247,16 +251,15 @@ module NetSuite
247
251
  'VI' => '_virginIslandsUSA',
248
252
  'WF' => '_wallisAndFutunaIslands',
249
253
  'EH' => '_westernSahara',
250
- 'WS' => '_westernSamoa',
254
+ 'WS' => '_samoa',
251
255
  'YE' => '_yemen',
252
- 'YU' => '_yugoslavia',
253
256
  'ZM' => '_zambia',
254
257
  'ZW' => '_zimbabwe'
255
258
  }
256
259
 
257
260
  def initialize(iso_or_name = '')
258
261
  if iso_or_name =~ /^[A-Z]{2}/
259
- @id = ISO_TO_NETSUITE.fetch(iso_or_name)
262
+ @id = iso_to_netsuite.fetch(iso_or_name)
260
263
  else
261
264
  @id = iso_or_name
262
265
  end
@@ -269,13 +272,22 @@ module NetSuite
269
272
  alias :eql? :==
270
273
 
271
274
  def to_iso
272
- ISO_TO_NETSUITE.key(@id)
275
+ iso_to_netsuite.key(@id)
273
276
  end
274
277
 
275
278
  def to_record
276
279
  @id
277
280
  end
278
281
 
282
+ def iso_to_netsuite
283
+ # NOTE GB country code changed on 2016_1
284
+ if NetSuite::Configuration.api_version <= "2015_2"
285
+ ISO_TO_NETSUITE.merge({ 'GB' => '_unitedKingdomGB' })
286
+ else
287
+ ISO_TO_NETSUITE
288
+ end
289
+ end
290
+
279
291
  end
280
292
  end
281
293
  end
@@ -17,9 +17,10 @@ module NetSuite
17
17
  # <platformCore:pageIndex>1</platformCore:pageIndex>
18
18
  # <platformCore:searchId>WEBSERVICES_738944_SB2_03012013650784545962753432_28d96bd280</platformCore:searchId>
19
19
 
20
- def initialize(response, result_class)
20
+ def initialize(response, result_class, credentials)
21
21
  @result_class = result_class
22
22
  @response = response
23
+ @credentials = credentials
23
24
 
24
25
  @total_records = response.body[:total_records].to_i
25
26
  @total_pages = response.body[:total_pages].to_i
@@ -28,8 +29,19 @@ module NetSuite
28
29
  if @total_records > 0
29
30
  if response.body.has_key?(:record_list)
30
31
  # basic search results
31
- record_list = response.body[:record_list][:record]
32
- 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
33
45
 
34
46
  record_list.each do |record|
35
47
  results << result_class.new(record)
@@ -98,8 +110,11 @@ module NetSuite
98
110
  yield results
99
111
 
100
112
  next_search = @result_class.search(
101
- search_id: @response.body[:search_id],
102
- page_index: @response.body[:page_index].to_i + 1
113
+ {
114
+ search_id: @response.body[:search_id],
115
+ page_index: @response.body[:page_index].to_i + 1
116
+ },
117
+ @credentials
103
118
  )
104
119
 
105
120
  @results = next_search.results
@@ -1,3 +1,5 @@
1
+ require 'date'
2
+
1
3
  module NetSuite
2
4
  module Utilities
3
5
  extend self
@@ -37,6 +39,36 @@ module NetSuite
37
39
  server_time_response.body[:get_server_time_response][:get_server_time_result][:server_time]
38
40
  end
39
41
 
42
+ def netsuite_data_center_urls(account_id)
43
+ data_center_call_response = NetSuite::Configuration.connection({
44
+ # NOTE force a production WSDL so the sandbox settings are ignored
45
+ # as of 1/20/18 NS will start using the account ID to determine
46
+ # if a account is sandbox (123_SB1) as opposed to using a sandbox domain
47
+
48
+ wsdl: 'https://webservices.netsuite.com/wsdl/v2017_2_0/netsuite.wsdl',
49
+
50
+ # NOTE don't inherit default namespace settings, it includes the API version
51
+ namespaces: {
52
+ 'xmlns:platformCore' => "urn:core_2017_2.platform.webservices.netsuite.com"
53
+ },
54
+
55
+ soap_header: {}
56
+ }).call(:get_data_center_urls, message: {
57
+ 'platformMsgs:account' => account_id
58
+ })
59
+
60
+ if data_center_call_response.success?
61
+ data_center_call_response.body[:get_data_center_urls_response][:get_data_center_urls_result][:data_center_urls]
62
+ else
63
+ false
64
+ end
65
+ end
66
+
67
+ # TODO consider what to dop with this duplicate data center implementation
68
+ def data_center_url(*args)
69
+ DataCenter.get(*args)
70
+ end
71
+
40
72
  def backoff(options = {})
41
73
  # TODO the default backoff attempts should be customizable the global config
42
74
  options[:attempts] ||= 8
@@ -46,7 +78,7 @@ module NetSuite
46
78
  begin
47
79
  count += 1
48
80
  yield
49
- rescue Exception => e
81
+ rescue StandardError => e
50
82
  exceptions_to_retry = [
51
83
  Errno::ECONNRESET,
52
84
  Errno::ETIMEDOUT,
@@ -83,12 +115,20 @@ module NetSuite
83
115
  # https://github.com/stripe/stripe-netsuite/issues/815
84
116
  if !e.message.include?("Only one request may be made against a session at a time") &&
85
117
  !e.message.include?('java.util.ConcurrentModificationException') &&
118
+ !e.message.include?('java.lang.NullPointerException') &&
119
+ !e.message.include?('java.lang.IllegalStateException') &&
120
+ !e.message.include?('java.lang.reflect.InvocationTargetException') &&
86
121
  !e.message.include?('com.netledger.common.exceptions.NLDatabaseOfflineException') &&
87
122
  !e.message.include?('com.netledger.database.NLConnectionUtil$NoCompanyDbsOnlineException') &&
88
123
  !e.message.include?('com.netledger.cache.CacheUnavailableException') &&
124
+ !e.message.include?('java.lang.IllegalStateException') &&
89
125
  !e.message.include?('An unexpected error occurred.') &&
126
+ !e.message.include?('An unexpected error has occurred. Technical Support has been alerted to this problem.') &&
90
127
  !e.message.include?('Session invalidation is in progress with different thread') &&
128
+ !e.message.include?('[missing resource APP:ERRORMESSAGE:WS_AN_UNEXPECTED_ERROR_OCCURRED] [missing resource APP:ERRORMESSAGE:ERROR_ID_1]') &&
91
129
  !e.message.include?('SuiteTalk concurrent request limit exceeded. Request blocked.') &&
130
+ # maintenance is the new outage: this message is being used for intermittent errors
131
+ !e.message.include?('The account you are trying to access is currently unavailable while we undergo our regularly scheduled maintenance.') &&
92
132
  !e.message.include?('The Connection Pool is not intialized.') &&
93
133
  # it looks like NetSuite mispelled their error message...
94
134
  !e.message.include?('The Connection Pool is not intiialized.')
@@ -109,15 +149,16 @@ module NetSuite
109
149
 
110
150
  def request_failed?(ns_object)
111
151
  return false if ns_object.errors.nil? || ns_object.errors.empty?
152
+ ns_object.errors.any? { |x| x.type == "ERROR" }
153
+ end
112
154
 
113
- warnings = ns_object.errors.select { |x| x.type == "WARN" }
114
- errors = ns_object.errors.select { |x| x.type == "ERROR" }
115
-
116
- # warnings.each do |warn|
117
- # log.warn(warn.message, code: warn.code)
118
- # end
155
+ def get_field_options(recordType, fieldName)
156
+ options = NetSuite::Records::BaseRefList.get_select_value(
157
+ field: fieldName,
158
+ recordType: recordType
159
+ )
119
160
 
120
- return errors.size > 0
161
+ options.base_refs
121
162
  end
122
163
 
123
164
  def get_item(ns_item_internal_id, opts = {})
@@ -133,6 +174,7 @@ module NetSuite
133
174
  ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::KitItem, ns_item_internal_id, opts)
134
175
  ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::SerializedInventoryItem, ns_item_internal_id, opts)
135
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)
136
178
 
137
179
  if ns_item.nil?
138
180
  fail NetSuite::RecordNotFound, "item with ID #{ns_item_internal_id} not found"
@@ -196,7 +238,11 @@ module NetSuite
196
238
  field_name = 'email'
197
239
  end
198
240
 
199
- field_name ||= 'name'
241
+ field_name ||= if record.to_s.end_with?('Item')
242
+ 'displayName'
243
+ else
244
+ 'name'
245
+ end
200
246
 
201
247
  # TODO remove backoff when it's built-in to search
202
248
  search = backoff { record.search({
@@ -217,25 +263,41 @@ module NetSuite
217
263
  nil
218
264
  end
219
265
 
220
- def data_center_url(*args)
221
- DataCenter.get(*args)
222
- end
223
-
224
266
  # http://mikebian.co/notes-on-dates-timezones-with-netsuites-suitetalk-api/
267
+ # https://wyeworks.com/blog/2016/6/22/behavior-changes-in-ruby-2.4
268
+ # https://github.com/rails/rails/commit/c9c5788a527b70d7f983e2b4b47e3afd863d9f48
269
+
225
270
  # assumes UTC0 unix timestamp
226
271
  def normalize_time_to_netsuite_date(unix_timestamp)
227
272
  # convert to date to eliminate hr/min/sec
228
- time = Time.at(unix_timestamp).utc.to_date.to_datetime
229
-
230
- offset = 8
231
- time = time.new_offset("-08:00")
232
-
233
- if time.to_time.dst?
234
- offset = 7
273
+ time = Time.at(unix_timestamp).
274
+ utc.
275
+ to_date.
276
+ to_datetime
277
+
278
+ # tzinfo allows us to determine the dst status of the time being passed in
279
+ # NetSuite requires that the time be passed to the API with the PDT TZ offset
280
+ # of the time passed in (i.e. not the current TZ offset of PDT)
281
+
282
+ if defined?(TZInfo)
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
293
+ else
294
+ # if tzinfo is not installed, let's give it our best guess: -7
295
+ offset = Rational(-7, 24)
235
296
  time = time.new_offset("-07:00")
236
297
  end
237
298
 
238
- (time + Rational(offset, 24)).iso8601
299
+ time = (time + (offset * -1))
300
+ time.iso8601
239
301
  end
240
302
 
241
303
  end