netsuite_rails 0.2.2 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +4 -2
  3. data/README.md +186 -10
  4. data/circle.yml +3 -0
  5. data/lib/netsuite_rails/configuration.rb +7 -5
  6. data/lib/netsuite_rails/netsuite_rails.rb +24 -4
  7. data/lib/netsuite_rails/poll_trigger.rb +10 -9
  8. data/lib/netsuite_rails/record_sync/poll_manager.rb +23 -11
  9. data/lib/netsuite_rails/record_sync/pull_manager.rb +2 -0
  10. data/lib/netsuite_rails/record_sync/push_manager.rb +76 -38
  11. data/lib/netsuite_rails/record_sync.rb +28 -11
  12. data/lib/netsuite_rails/routines/company_contact_match.rb +98 -0
  13. data/lib/netsuite_rails/spec/disabler.rb +27 -0
  14. data/lib/netsuite_rails/spec/query_helpers.rb +93 -0
  15. data/lib/netsuite_rails/spec/spec_helper.rb +2 -79
  16. data/lib/netsuite_rails/sync_trigger.rb +40 -17
  17. data/lib/netsuite_rails/tasks/netsuite.rb +33 -4
  18. data/lib/netsuite_rails/transformations.rb +59 -19
  19. data/lib/netsuite_rails/url_helper.rb +45 -12
  20. data/netsuite_rails.gemspec +2 -2
  21. data/spec/models/configuration_spec.rb +11 -0
  22. data/spec/models/poll_manager_spec.rb +11 -2
  23. data/spec/models/poll_trigger_spec.rb +31 -11
  24. data/spec/models/record_sync/push_manager_spec.rb +51 -0
  25. data/spec/models/record_sync_spec.rb +16 -0
  26. data/spec/models/spec_helper_spec.rb +1 -2
  27. data/spec/models/transformations_spec.rb +62 -0
  28. data/spec/models/url_helper_spec.rb +20 -9
  29. data/spec/spec_helper.rb +19 -0
  30. data/spec/support/example_models.rb +33 -1
  31. metadata +19 -25
  32. data/.travis.yml +0 -3
  33. data/lib/netsuite_rails/netsuite_configure.rb +0 -14
  34. data/spec/support/netsuite_rails.rb +0 -1
@@ -8,7 +8,10 @@ module NetSuiteRails
8
8
  # TODO check to see if anything is changed before moving forward
9
9
  # if changes_keys.blank? && local_record.netsuite_manual_fields
10
10
 
11
- if opts[:modified_fields]
11
+ # always include the full netsuite field mapping, regardless of which
12
+ # fields were modfified locally, when initially creating the netsuite record
13
+
14
+ if opts[:modified_fields] && !local_record.new_netsuite_record?
12
15
  # if Array, we need to convert info fields hash based on the record definition
13
16
  if opts[:modified_fields].is_a?(Array)
14
17
  opts[:modified_fields] = all_netsuite_fields(local_record).select { |k,v| opts[:modified_fields].include?(k) }
@@ -21,17 +24,10 @@ module NetSuiteRails
21
24
 
22
25
  local_record.netsuite_execute_callbacks(local_record.class.before_netsuite_push, netsuite_record)
23
26
 
24
- if !local_record.new_netsuite_record?
25
- push_update(local_record, netsuite_record, opts)
26
- else
27
+ if opts[:push_method] == :upsert || local_record.new_netsuite_record?
27
28
  push_add(local_record, netsuite_record, opts)
28
- end
29
-
30
- # :aggressive is for custom fields which are based on input – need pull updated values after
31
- # the push to netsuite to retrieve the calculated values
32
-
33
- if local_record.netsuite_sync == :aggressive
34
- local_record.netsuite_pull
29
+ else
30
+ push_update(local_record, netsuite_record, opts)
35
31
  end
36
32
 
37
33
  local_record.netsuite_execute_callbacks(local_record.class.after_netsuite_push, netsuite_record)
@@ -40,12 +36,19 @@ module NetSuiteRails
40
36
  end
41
37
 
42
38
  def push_add(local_record, netsuite_record, opts = {})
43
- if netsuite_record.add
44
- # update_column to avoid triggering another save
45
- local_record.update_column(:netsuite_id, netsuite_record.internal_id)
39
+ # push_method is either :add or :upsert
40
+ if netsuite_record.send(opts[:push_method] || :add)
41
+ Rails.logger.info "NetSuite: action=#{opts[:push_method]}, local_record=#{local_record.class}[#{local_record.id}]" +
42
+ "netsuite_record_type=#{netsuite_record.class}, netsuite_record_id=#{netsuite_record.internal_id}"
43
+
44
+ if is_active_record_model?(local_record)
45
+ # update_column to avoid triggering another save
46
+ local_record.update_column(:netsuite_id, netsuite_record.internal_id)
47
+ else
48
+ netsuite_record.internal_id
49
+ end
46
50
  else
47
- # TODO use NS error class
48
- raise "NetSuite: error creating record #{netsuite_record.errors}"
51
+ raise "NetSuite: error. action=#{opts[:push_method]}, netsuite_record_type=#{netsuite_record.class}, errors=#{netsuite_record.errors}"
49
52
  end
50
53
  end
51
54
 
@@ -54,8 +57,17 @@ module NetSuiteRails
54
57
  # NS could have logic which could change field functionality depending on
55
58
  # input data; it's safest to limit the number of field changes pushed to NS
56
59
 
60
+ # exclude fields that map to procs: they don't indicate which netsuite field
61
+ # the local rails field maps to, so the user must specify this manually in `netsuite_manual_fields`
62
+
63
+ # TODO add option for model to mark `custom_field_list = true` if custom field mapping to a
64
+ # proc is detected. This is helpful for users mapping a local field to a custom field
65
+
57
66
  custom_field_list = local_record.netsuite_field_map[:custom_field_list] || {}
67
+ custom_field_list = custom_field_list.select { |local_field, netsuite_field| !netsuite_field.is_a?(Proc) }
68
+
58
69
  modified_fields_list = opts[:modified_fields]
70
+ modified_fields_list = modified_fields_list.select { |local_field, netsuite_field| !netsuite_field.is_a?(Proc) }
59
71
 
60
72
  update_list = {}
61
73
 
@@ -87,7 +99,10 @@ module NetSuiteRails
87
99
  update_list[:rec_type] = netsuite_record.rec_type
88
100
  end
89
101
 
90
- # TODO consider using upsert here
102
+ Rails.logger.info "NetSuite: Update #{netsuite_record.class} #{netsuite_record.internal_id}, list #{update_list.keys}"
103
+
104
+ # don't update if list is empty
105
+ return if update_list.empty?
91
106
 
92
107
  if netsuite_record.update(update_list)
93
108
  true
@@ -97,19 +112,13 @@ module NetSuiteRails
97
112
  end
98
113
 
99
114
  def build_netsuite_record(local_record, opts = {})
100
- netsuite_record = build_netsuite_record_reference(local_record)
101
-
102
- # TODO need to normalize datetime fields
115
+ netsuite_record = build_netsuite_record_reference(local_record, opts)
103
116
 
104
117
  all_field_list = opts[:modified_fields]
105
118
  custom_field_list = local_record.netsuite_field_map[:custom_field_list] || {}
106
119
  field_hints = local_record.netsuite_field_hints
107
120
 
108
- reflections = if NetSuiteRails.rails4?
109
- local_record.class.reflections
110
- else
111
- local_record.reflections
112
- end
121
+ reflections = relationship_attributes_list(local_record)
113
122
 
114
123
  all_field_list.each do |local_field, netsuite_field|
115
124
  # allow Procs as field mapping in the record definition for custom mapping
@@ -118,7 +127,7 @@ module NetSuiteRails
118
127
  next
119
128
  end
120
129
 
121
- # TODO pretty sure this will break if we are dealing with has_many
130
+ # TODO pretty sure this will break if we are dealing with has_many
122
131
 
123
132
  netsuite_field_value = if reflections.has_key?(local_field)
124
133
  if (remote_internal_id = local_record.send(local_field).try(:netsuite_id)).present?
@@ -131,7 +140,7 @@ module NetSuiteRails
131
140
  end
132
141
 
133
142
  if field_hints.has_key?(local_field) && netsuite_field_value.present?
134
- netsuite_field_value = NetSuiteRails::Transformations.transform(field_hints[local_field], netsuite_field_value)
143
+ netsuite_field_value = NetSuiteRails::Transformations.transform(field_hints[local_field], netsuite_field_value, :push)
135
144
  end
136
145
 
137
146
  # TODO should we skip setting nil values completely? What if we want to nil out fields on update?
@@ -148,10 +157,16 @@ module NetSuiteRails
148
157
  netsuite_record
149
158
  end
150
159
 
151
- def build_netsuite_record_reference(local_record)
160
+ def build_netsuite_record_reference(local_record, opts = {})
152
161
  # must set internal_id for records on new; will be set to nil if new record
153
162
 
154
- netsuite_record = local_record.netsuite_record_class.new(internal_id: local_record.netsuite_id)
163
+ init_hash = if opts[:use_external_id]
164
+ { external_id: local_record.netsuite_external_id }
165
+ else
166
+ { internal_id: local_record.netsuite_id }
167
+ end
168
+
169
+ netsuite_record = local_record.netsuite_record_class.new(init_hash)
155
170
 
156
171
  if local_record.netsuite_custom_record?
157
172
  netsuite_record.rec_type = NetSuite::Records::CustomRecord.new(internal_id: local_record.class.netsuite_custom_record_type_id)
@@ -163,7 +178,11 @@ module NetSuiteRails
163
178
  def modified_local_fields(local_record)
164
179
  synced_netsuite_fields = all_netsuite_fields(local_record)
165
180
 
166
- changed_keys = changed_attributes(local_record)
181
+ changed_keys = if is_active_record_model?(local_record)
182
+ changed_attributes(local_record)
183
+ else
184
+ local_record.changed_attributes
185
+ end
167
186
 
168
187
  # filter out unchanged keys when updating record
169
188
  unless local_record.new_netsuite_record?
@@ -186,11 +205,7 @@ module NetSuiteRails
186
205
 
187
206
  # TODO think about has_many / join table changes
188
207
 
189
- reflections = if NetSuiteRails.rails4?
190
- local_record.class.reflections
191
- else
192
- local_record.reflections
193
- end
208
+ reflections = relationship_attributes_list(local_record)
194
209
 
195
210
  association_field_key_mapping = reflections.values.reject(&:collection?).inject({}) do |h, a|
196
211
  begin
@@ -205,8 +220,16 @@ module NetSuiteRails
205
220
 
206
221
  changed_attributes_keys = local_record.changed_attributes.keys
207
222
 
208
- # TODO documentation about serialized values
209
- changed_attributes_keys += local_record.serialized_attributes.keys.map do |k|
223
+ serialized_attrs = if NetSuiteRails.rails4?
224
+ local_record.class.serialized_attributes
225
+ else
226
+ local_record.serialized_attributes
227
+ end
228
+
229
+ # changes_attributes does not track serialized attributes, although it does track the storage key
230
+ # if a serialized attribute storage key is dirty assume that all keys in the hash are dirty as well
231
+
232
+ changed_attributes_keys += serialized_attrs.keys.map do |k|
210
233
  local_record.send(k.to_sym).keys.map(&:to_s)
211
234
  end.flatten
212
235
 
@@ -216,9 +239,24 @@ module NetSuiteRails
216
239
  end
217
240
  end
218
241
 
242
+ def relationship_attributes_list(local_record)
243
+ if is_active_record_model?(local_record)
244
+ if NetSuiteRails.rails4?
245
+ local_record.class.reflections
246
+ else
247
+ local_record.reflections
248
+ end
249
+ else
250
+ local_record.respond_to?(:reflections) ? local_record.reflections : {}
251
+ end
252
+ end
253
+
254
+ def is_active_record_model?(local_record)
255
+ local_record.class.ancestors.include?(ActiveRecord::Base)
256
+ end
219
257
 
220
258
  end
221
259
  end
222
260
 
223
261
  end
224
- end
262
+ end
@@ -84,7 +84,7 @@ module NetSuiteRails
84
84
  self.netsuite_record_class == NetSuite::Records::CustomRecord
85
85
  end
86
86
 
87
- # :read, :aggressive (push & update on save), :write_only, :read_write
87
+ # :read, :write_only, :read_write
88
88
  def netsuite_sync(flag = nil, opts = {})
89
89
  if !flag.nil?
90
90
  self.netsuite_sync_options = opts
@@ -96,7 +96,11 @@ module NetSuiteRails
96
96
  end
97
97
 
98
98
  module InstanceMethods
99
- attr_accessor :netsuite_manual_fields
99
+ attr_writer :netsuite_manual_fields
100
+
101
+ def netsuite_manual_fields
102
+ @netsuite_manual_fields ||= []
103
+ end
100
104
 
101
105
  # these methods are here for easy model override
102
106
 
@@ -130,12 +134,23 @@ module NetSuiteRails
130
134
  @netsuite_pulled ||= false
131
135
  end
132
136
 
137
+ def netsuite_async_jobs?
138
+ self.netsuite_sync_options[:sync_mode] == :async || (self.netsuite_sync_options[:sync_mode].blank? && NetSuiteRails::Configuration.netsuite_sync_mode == :async)
139
+ end
140
+
141
+ # TODO need to support the opts hash
133
142
  def netsuite_pull(opts = {})
134
- # TODO need to support the opts hash
135
143
  netsuite_extract_from_record(netsuite_pull_record)
144
+
145
+ if self.netsuite_async_jobs?
146
+ # without callbacks?
147
+ self.save
148
+ end
136
149
  end
137
150
 
138
151
  def netsuite_pull_record
152
+ # TODO support use_external_id / netsuite_external_id
153
+
139
154
  if netsuite_custom_record?
140
155
  NetSuite::Records::CustomRecord.get(
141
156
  internal_id: self.netsuite_id,
@@ -152,6 +167,8 @@ module NetSuiteRails
152
167
 
153
168
  # TODO move this login into separate service object
154
169
  def netsuite_extract_from_record(netsuite_record)
170
+ Rails.logger.info "NetSuite: Pull #{netsuite_record.class} #{netsuite_record.internal_id}"
171
+
155
172
  @netsuite_pulling = true
156
173
 
157
174
  field_hints = self.netsuite_field_hints
@@ -161,10 +178,11 @@ module NetSuiteRails
161
178
  all_field_list = self.netsuite_field_map.except(:custom_field_list) || {}
162
179
  all_field_list.merge!(custom_field_list)
163
180
 
164
- # self.netsuite_normalize_datetimes(:pull)
181
+ # TODO should have a helper module for common push/pull methods
182
+ reflection_attributes = NetSuiteRails::RecordSync::PushManager.relationship_attributes_list(self)
165
183
 
166
184
  # handle non-collection associations
167
- association_keys = self.reflections.values.reject(&:collection?).map(&:name)
185
+ association_keys = reflection_attributes.values.reject(&:collection?).map(&:name)
168
186
 
169
187
  all_field_list.each do |local_field, netsuite_field|
170
188
  is_custom_field = custom_field_list.keys.include?(local_field)
@@ -186,7 +204,10 @@ module NetSuiteRails
186
204
  end
187
205
 
188
206
  if association_keys.include?(local_field)
189
- field_value = self.reflections[local_field].klass.where(netsuite_id: field_value.internal_id).first_or_initialize
207
+ field_value = reflection_attributes[local_field].
208
+ klass.
209
+ where(netsuite_id: field_value.internal_id).
210
+ first_or_initialize
190
211
  elsif is_custom_field
191
212
  field_value = NetSuiteRails::RecordSync::PullManager.extract_custom_field_value(field_value)
192
213
  else
@@ -195,12 +216,8 @@ module NetSuiteRails
195
216
 
196
217
  # TODO should we just check for nil? vs present?
197
218
 
198
- # TODO should be moved to Transformations with a direction flag
199
219
  if field_hints.has_key?(local_field) && field_value.present?
200
- case field_hints[local_field]
201
- when :datetime
202
- field_value = field_value.change(offset: "00:00") - (Time.zone.utc_offset / 3600).hours + (8 + NetSuiteRails::Configuration.netsuite_instance_time_zone_offset).hours
203
- end
220
+ field_value = NetSuiteRails::Transformations.transform(field_hints[local_field], field_value, :pull)
204
221
  end
205
222
 
206
223
  self.send(:"#{local_field}=", field_value)
@@ -0,0 +1,98 @@
1
+ module NetSuiteRails
2
+ module Routines
3
+ module CompanyContactMatch
4
+ extend self
5
+
6
+ def match(company_customer, contact_data)
7
+ # TODO set page size to a large number for this search
8
+ search = NetSuite::Records::Contact.search({
9
+ customerJoin: [
10
+ {
11
+ field: 'internalId',
12
+ operator: 'anyOf',
13
+ value: [
14
+ NetSuite::Records::Customer.new(internal_id: company_customer.internal_id)
15
+ ]
16
+ }
17
+ ]
18
+ })
19
+
20
+ match_data = {
21
+ email: contact_data[:email].dup,
22
+ first_name: contact_data[:first_name].dup,
23
+ last_name: contact_data[:last_name].dup
24
+ }
25
+
26
+ match_data.
27
+ values.
28
+ each(&:strip!).
29
+ each(&:downcase!)
30
+
31
+ # TODO search error checking
32
+
33
+ # try name match first; NS will throw an error if a contact is created or updated if the name already exists
34
+ search.results.each do |contact|
35
+ contact_first_name = contact.first_name.downcase.strip rescue ''
36
+ contact_last_name = contact.last_name.downcase.strip rescue ''
37
+
38
+ # if no email match & name data is present try fuzzy matching
39
+ if match_data[:first_name] && match_data[:last_name] && !contact_first_name.empty? && !contact_last_name.empty?
40
+
41
+ # TODO consider `self.fuzzy_name_matches?(contact_first_name, contact_last_name, match_data[:first_name], match_data[:last_name])`
42
+ if contact_first_name == match_data[:first_name] && contact_last_name == match_data[:last_name]
43
+ return contact
44
+ end
45
+ end
46
+ end
47
+
48
+ # try email match second
49
+ # search.results.each do |contact|
50
+ # contact_first_name = contact.first_name.downcase.strip rescue ''
51
+ # contact_last_name = contact.last_name.downcase.strip rescue ''
52
+
53
+ # # match on email
54
+ # if match_data[:email] && contact.email && contact.email.downcase.strip == match_data[:email]
55
+ # if match_data[:first_name] != contact_first_name || match_data[:last_name] != contact_last_name
56
+ # # first name and/or last name did not match the input, update contact information
57
+
58
+ # result = contact.update(
59
+ # # use the first & last name from the payload; the match_data versions have been transformed
60
+ # first_name: order_payload[:shipping_address][:firstname],
61
+ # last_name: order_payload[:shipping_address][:lastname]
62
+ # )
63
+
64
+ # unless result
65
+ # raise 'error updating name on contact placing order'
66
+ # end
67
+ # end
68
+
69
+ # return contact
70
+ # end
71
+ # end
72
+
73
+ nil
74
+ end
75
+
76
+ # TODO consider optionally using fuzzy name matches in the future
77
+ # def fuzzy_name_matches?(first_name_1, last_name_1, first_name_2, last_name_2)
78
+ # @fuzzy_comparison ||= FuzzyStringMatch::JaroWinkler.create
79
+
80
+ # # Jarow-Winkler returns 1 for exact match
81
+ # if @fuzzy_comparison.getDistance(last_name_1, last_name_2) > 0.90
82
+ # # check for a match on the first name
83
+ # if @fuzzy_comparison.getDistance(first_name_1, first_name_2) > 0.90
84
+ # return true
85
+ # end
86
+
87
+ # # if fuzzy on first name failed; try to see if there are any nickname equivilents
88
+ # if Monikers.equivalents?(first_name_1, first_name_2)
89
+ # return true
90
+ # end
91
+ # end
92
+
93
+ # false
94
+ # end
95
+
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,27 @@
1
+ module NetSuiteRails
2
+ module Spec
3
+ module TestDisabler
4
+
5
+ def disable_netsuite_communication
6
+ before do
7
+ @_push_disabled = NetSuiteRails::Configuration.netsuite_push_disabled
8
+ @_pull_disabled = NetSuiteRails::Configuration.netsuite_pull_disabled
9
+
10
+ NetSuiteRails::Configuration.netsuite_push_disabled true
11
+ NetSuiteRails::Configuration.netsuite_pull_disabled true
12
+ end
13
+
14
+ after do
15
+ NetSuiteRails::Configuration.netsuite_push_disabled @_push_disabled
16
+ NetSuiteRails::Configuration.netsuite_pull_disabled @_pull_disabled
17
+ end
18
+ end
19
+
20
+
21
+ end
22
+ end
23
+ end
24
+
25
+ RSpec.configure do |config|
26
+ config.extend NetSuiteRails::Spec::TestDisabler
27
+ end
@@ -0,0 +1,93 @@
1
+ module NetSuiteRails
2
+ module Spec
3
+ module QueryHelpers
4
+
5
+ def self.included(base)
6
+ base.before { netsuite_timestamp(DateTime.now) }
7
+ end
8
+
9
+ def netsuite_timestamp(stamp = nil)
10
+ if stamp.nil?
11
+ @netsuite_timestamp ||= (Time.now - (60 * 2)).to_datetime
12
+ else
13
+ @netsuite_timestamp = stamp
14
+ end
15
+ end
16
+
17
+ def get_last_netsuite_object(record)
18
+ # TODO support passing custom record ref
19
+
20
+ if record.is_a?(Class)
21
+ record_class = record
22
+ is_custom_record = false
23
+ else
24
+ record_class = record.netsuite_record_class
25
+ is_custom_record = record.netsuite_custom_record?
26
+ end
27
+
28
+ search = record_class.search({
29
+ criteria: {
30
+ basic:
31
+ (
32
+ if is_custom_record
33
+ [
34
+ {
35
+ field: 'recType',
36
+ operator: 'is',
37
+ value: NetSuite::Records::CustomRecordRef.new(internal_id: record.class.netsuite_custom_record_type_id)
38
+ },
39
+ {
40
+ field: 'lastModified',
41
+ operator: 'after',
42
+ value: netsuite_timestamp
43
+ }
44
+ ]
45
+ else
46
+ [
47
+ {
48
+ field: 'lastModifiedDate',
49
+ operator: 'after',
50
+ value: netsuite_timestamp
51
+ }
52
+ ]
53
+ end +
54
+
55
+ if [ NetSuite::Records::SalesOrder, NetSuite::Records::ItemFulfillment, NetSuite::Records::Invoice ].include?(record_class)
56
+ [
57
+ {
58
+ field: 'type',
59
+ operator: 'anyOf',
60
+ value: [ '_' + record_class.name.demodulize.lower_camelcase ]
61
+ }
62
+ ]
63
+ else
64
+ []
65
+ end
66
+ )
67
+ }
68
+ })
69
+
70
+ return nil if search.results.blank?
71
+
72
+ if is_custom_record
73
+ NetSuite::Records::CustomRecord.get(
74
+ internal_id: search.results.first.internal_id.to_i,
75
+ type_id: record.class.netsuite_custom_record_type_id
76
+ )
77
+ else
78
+ record_class.get(search.results.first.internal_id.to_i)
79
+ end
80
+ end
81
+
82
+ # convenience method for inspecting objects in a live IRB session
83
+ def netsuite_url(object)
84
+ `open "#{NetSuiteRails::UrlHelper.netsuite_url(object)}"`
85
+ end
86
+
87
+ end
88
+ end
89
+ end
90
+
91
+ RSpec.configure do |config|
92
+ config.include NetSuiteRails::Spec::QueryHelpers
93
+ end
@@ -1,86 +1,9 @@
1
1
  require 'netsuite'
2
2
  require 'savon/mock/spec_helper'
3
3
 
4
- module NetSuiteRails::TestHelpers
5
-
6
- def self.included(base)
7
- base.before { netsuite_timestamp(DateTime.now) }
8
- end
9
-
10
- def netsuite_timestamp(stamp = nil)
11
- if stamp.nil?
12
- @netsuite_timestamp ||= (Time.now - (60 * 2)).to_datetime
13
- else
14
- @netsuite_timestamp = stamp
15
- end
16
- end
17
-
18
- def get_last_netsuite_object(record)
19
- # TODO support passing custom record ref
20
-
21
- if record.is_a?(Class)
22
- record_class = record
23
- is_custom_record = false
24
- else
25
- record_class = record.netsuite_record_class
26
- is_custom_record = record.netsuite_custom_record?
27
- end
28
-
29
- search = record_class.search({
30
- criteria: {
31
- basic:
32
- (
33
- if is_custom_record
34
- [
35
- {
36
- field: 'recType',
37
- operator: 'is',
38
- value: NetSuite::Records::CustomRecordRef.new(internal_id: record.class.netsuite_custom_record_type_id)
39
- },
40
- {
41
- field: 'lastModified',
42
- operator: 'after',
43
- value: netsuite_timestamp
44
- }
45
- ]
46
- else
47
- [
48
- {
49
- field: 'lastModifiedDate',
50
- operator: 'after',
51
- value: netsuite_timestamp
52
- }
53
- ]
54
- end +
55
-
56
- if record_class == NetSuite::Records::SalesOrder
57
- [
58
- {
59
- field: 'type',
60
- operator: 'anyOf',
61
- value: [ '_salesOrder' ]
62
- }
63
- ]
64
- else
65
- []
66
- end
67
- )
68
- }
69
- })
70
-
71
- if is_custom_record
72
- NetSuite::Records::CustomRecord.get(
73
- internal_id: search.results.first.internal_id.to_i,
74
- type_id: record.class.netsuite_custom_record_type_id
75
- )
76
- else
77
- record_class.get(search.results.first.internal_id.to_i)
78
- end
79
- end
80
-
81
- end
4
+ require 'netsuite_rails/spec/query_helpers'
5
+ require 'netsuite_rails/spec/disabler'
82
6
 
83
7
  RSpec.configure do |config|
84
- config.include NetSuiteRails::TestHelpers, type: :feature
85
8
  config.include Savon::SpecHelper
86
9
  end