netsuite_rails 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +3 -0
  3. data/Gemfile +17 -7
  4. data/README.md +9 -4
  5. data/lib/netsuite_rails/configuration.rb +3 -1
  6. data/lib/netsuite_rails/list_sync/poll_manager.rb +30 -0
  7. data/lib/netsuite_rails/list_sync.rb +2 -2
  8. data/lib/netsuite_rails/netsuite_rails.rb +13 -3
  9. data/lib/netsuite_rails/poll_timestamp.rb +5 -0
  10. data/lib/netsuite_rails/{poll_manager.rb → poll_trigger.rb} +18 -3
  11. data/lib/netsuite_rails/record_sync/poll_manager.rb +186 -0
  12. data/lib/netsuite_rails/record_sync/pull_manager.rb +10 -137
  13. data/lib/netsuite_rails/record_sync/push_manager.rb +59 -21
  14. data/lib/netsuite_rails/record_sync.rb +142 -140
  15. data/lib/netsuite_rails/spec/spec_helper.rb +34 -6
  16. data/lib/netsuite_rails/sync_trigger.rb +80 -75
  17. data/lib/netsuite_rails/tasks/netsuite.rb +26 -30
  18. data/lib/netsuite_rails/url_helper.rb +12 -3
  19. data/netsuite_rails.gemspec +3 -3
  20. data/spec/models/poll_manager_spec.rb +45 -0
  21. data/spec/models/poll_trigger_spec.rb +26 -0
  22. data/spec/models/record_sync/push_manager_spec.rb +0 -0
  23. data/spec/models/spec_helper_spec.rb +29 -0
  24. data/spec/models/sync_trigger_spec.rb +62 -0
  25. data/spec/models/url_helper_spec.rb +23 -0
  26. data/spec/spec_helper.rb +17 -1
  27. data/spec/support/config/database.yml +11 -0
  28. data/spec/support/dynamic_models/class_builder.rb +48 -0
  29. data/spec/support/dynamic_models/model_builder.rb +83 -0
  30. data/spec/support/example_models.rb +31 -0
  31. data/spec/support/netsuite_rails.rb +1 -0
  32. data/spec/support/test_application.rb +55 -0
  33. metadata +36 -10
  34. data/lib/netsuite_rails/list_sync/pull_manager.rb +0 -33
@@ -4,18 +4,27 @@ module NetSuiteRails
4
4
  class PushManager
5
5
  class << self
6
6
 
7
- def push(local_record, opts)
7
+ def push(local_record, opts = {})
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
- netsuite_record = build_netsuite_record(local_record)
11
+ if opts[:modified_fields]
12
+ # if Array, we need to convert info fields hash based on the record definition
13
+ if opts[:modified_fields].is_a?(Array)
14
+ opts[:modified_fields] = all_netsuite_fields(local_record).select { |k,v| opts[:modified_fields].include?(k) }
15
+ end
16
+ else
17
+ opts[:modified_fields] = modified_local_fields(local_record)
18
+ end
19
+
20
+ netsuite_record = build_netsuite_record(local_record, opts)
12
21
 
13
22
  local_record.netsuite_execute_callbacks(local_record.class.before_netsuite_push, netsuite_record)
14
23
 
15
24
  if !local_record.new_netsuite_record?
16
- push_update(local_record, netsuite_record)
25
+ push_update(local_record, netsuite_record, opts)
17
26
  else
18
- push_add(local_record, netsuite_record)
27
+ push_add(local_record, netsuite_record, opts)
19
28
  end
20
29
 
21
30
  # :aggressive is for custom fields which are based on input – need pull updated values after
@@ -30,7 +39,7 @@ module NetSuiteRails
30
39
  true
31
40
  end
32
41
 
33
- def push_add(local_record, netsuite_record)
42
+ def push_add(local_record, netsuite_record, opts = {})
34
43
  if netsuite_record.add
35
44
  # update_column to avoid triggering another save
36
45
  local_record.update_column(:netsuite_id, netsuite_record.internal_id)
@@ -40,17 +49,17 @@ module NetSuiteRails
40
49
  end
41
50
  end
42
51
 
43
- def push_update(local_record, netsuite_record)
52
+ def push_update(local_record, netsuite_record, opts = {})
44
53
  # build change hash to limit the number of fields pushed to NS on change
45
54
  # NS could have logic which could change field functionality depending on
46
55
  # input data; it's safest to limit the number of field changes pushed to NS
47
56
 
48
57
  custom_field_list = local_record.netsuite_field_map[:custom_field_list] || {}
49
- all_field_list = eligible_local_fields(local_record)
58
+ modified_fields_list = opts[:modified_fields]
50
59
 
51
60
  update_list = {}
52
61
 
53
- all_field_list.each do |local_field, netsuite_field|
62
+ modified_fields_list.each do |local_field, netsuite_field|
54
63
  if custom_field_list.keys.include?(local_field)
55
64
  # if custom field has changed, mark and copy over customFieldList later
56
65
  update_list[:custom_field_list] = true
@@ -87,15 +96,21 @@ module NetSuiteRails
87
96
  end
88
97
  end
89
98
 
90
- def build_netsuite_record(local_record)
99
+ def build_netsuite_record(local_record, opts = {})
91
100
  netsuite_record = build_netsuite_record_reference(local_record)
92
101
 
93
102
  # TODO need to normalize datetime fields
94
103
 
95
- all_field_list = eligible_local_fields(local_record)
104
+ all_field_list = opts[:modified_fields]
96
105
  custom_field_list = local_record.netsuite_field_map[:custom_field_list] || {}
97
106
  field_hints = local_record.netsuite_field_hints
98
107
 
108
+ reflections = if NetSuiteRails.rails4?
109
+ local_record.class.reflections
110
+ else
111
+ local_record.reflections
112
+ end
113
+
99
114
  all_field_list.each do |local_field, netsuite_field|
100
115
  # allow Procs as field mapping in the record definition for custom mapping
101
116
  if netsuite_field.is_a?(Proc)
@@ -105,7 +120,7 @@ module NetSuiteRails
105
120
 
106
121
  # TODO pretty sure this will break if we are dealing with has_many
107
122
 
108
- netsuite_field_value = if local_record.reflections.has_key?(local_field)
123
+ netsuite_field_value = if reflections.has_key?(local_field)
109
124
  if (remote_internal_id = local_record.send(local_field).try(:netsuite_id)).present?
110
125
  { internal_id: remote_internal_id }
111
126
  else
@@ -145,20 +160,24 @@ module NetSuiteRails
145
160
  netsuite_record
146
161
  end
147
162
 
148
- def eligible_local_fields(local_record)
149
- custom_field_list = local_record.netsuite_field_map[:custom_field_list] || {}
150
- all_field_list = local_record.netsuite_field_map.except(:custom_field_list) || {}
151
-
152
- all_field_list.merge!(custom_field_list)
163
+ def modified_local_fields(local_record)
164
+ synced_netsuite_fields = all_netsuite_fields(local_record)
153
165
 
154
166
  changed_keys = changed_attributes(local_record)
155
167
 
156
168
  # filter out unchanged keys when updating record
157
169
  unless local_record.new_netsuite_record?
158
- all_field_list.select! { |k,v| changed_keys.include?(k) }
170
+ synced_netsuite_fields.select! { |k,v| changed_keys.include?(k) }
159
171
  end
160
172
 
161
- all_field_list
173
+ synced_netsuite_fields
174
+ end
175
+
176
+ def all_netsuite_fields(local_record)
177
+ custom_netsuite_field_list = local_record.netsuite_field_map[:custom_field_list] || {}
178
+ standard_netsuite_field_list = local_record.netsuite_field_map.except(:custom_field_list) || {}
179
+
180
+ custom_netsuite_field_list.merge(standard_netsuite_field_list)
162
181
  end
163
182
 
164
183
  def changed_attributes(local_record)
@@ -167,13 +186,32 @@ module NetSuiteRails
167
186
 
168
187
  # TODO think about has_many / join table changes
169
188
 
170
- association_field_key_mapping = local_record.reflections.values.reject(&:collection?).inject({}) do |h, a|
171
- h[a.association_foreign_key.to_sym] = a.name
189
+ reflections = if NetSuiteRails.rails4?
190
+ local_record.class.reflections
191
+ else
192
+ local_record.reflections
193
+ end
194
+
195
+ association_field_key_mapping = reflections.values.reject(&:collection?).inject({}) do |h, a|
196
+ begin
197
+ h[a.association_foreign_key.to_sym] = a.name
198
+ rescue Exception => e
199
+ # occurs when `has_one through:` exists on a record but `through` is not a valid reference
200
+ Rails.logger.error "NetSuite: error detecting foreign key #{a.name}"
201
+ end
202
+
172
203
  h
173
204
  end
174
205
 
206
+ changed_attributes_keys = local_record.changed_attributes.keys
207
+
208
+ # TODO documentation about serialized values
209
+ changed_attributes_keys += local_record.serialized_attributes.keys.map do |k|
210
+ local_record.send(k.to_sym).keys.map(&:to_s)
211
+ end.flatten
212
+
175
213
  # convert relationship symbols from :object_id to :object
176
- local_record.changed_attributes.keys.map do |k|
214
+ changed_attributes_keys.map do |k|
177
215
  association_field_key_mapping[k.to_sym] || k.to_sym
178
216
  end
179
217
  end
@@ -2,72 +2,81 @@ module NetSuiteRails
2
2
  module RecordSync
3
3
 
4
4
  def self.included(klass)
5
+ klass.class_eval do
6
+ class_attribute :netsuite_settings
7
+
8
+ self.netsuite_settings = {
9
+ before_netsuite_push: [],
10
+ after_netsuite_push: [],
11
+ after_netsuite_pull: [],
12
+
13
+ netsuite_sync: :read,
14
+ netsuite_field_map: {},
15
+ netsuite_field_hints: {},
16
+ netsuite_record_class: nil,
17
+ }
18
+
19
+ cattr_accessor :netsuite_custom_record_type_id
20
+ cattr_accessor :netsuite_sync_options
21
+ end
22
+
5
23
  klass.send(:extend, ClassMethods)
24
+ klass.send(:include, InstanceMethods)
6
25
 
7
26
  SyncTrigger.attach(klass)
8
- PollManager.attach(klass)
27
+ PollTrigger.attach(klass)
9
28
  end
10
29
 
11
30
  module ClassMethods
12
31
  def netsuite_poll(opts = {})
13
- RecordSync::PullManager.poll(self, opts)
32
+ RecordSync::PollManager.poll(self, opts)
14
33
  end
15
34
 
16
35
  attr_accessor :netsuite_custom_record_type_id
17
36
  attr_accessor :netsuite_sync_options
18
- attr_accessor :netsuite_credentials
19
37
 
20
38
  # TODO is there a better way to implement callback chains?
21
39
  # https://github.com/rails/rails/blob/0c0f278ab20f3042cdb69604166e18a61f8605ad/activesupport/lib/active_support/callbacks.rb#L491
22
40
 
23
41
  def before_netsuite_push(callback = nil, &block)
24
- @before_netsuite_push ||= []
25
- @before_netsuite_push << (callback || block) if callback || block
26
- @before_netsuite_push
42
+ self.netsuite_settings[:before_netsuite_push] << (callback || block) if callback || block
43
+ self.netsuite_settings[:before_netsuite_push]
27
44
  end
28
45
 
29
46
  def after_netsuite_push(callback = nil, &block)
30
- @after_netsuite_push ||= []
31
- @after_netsuite_push << (callback || block) if callback || block
32
- @after_netsuite_push
47
+ self.netsuite_settings[:after_netsuite_push] << (callback || block) if callback || block
48
+ self.netsuite_settings[:after_netsuite_push]
33
49
  end
34
50
 
35
51
  def after_netsuite_pull(callback = nil, &block)
36
- @after_netsuite_pull ||= []
37
- @after_netsuite_pull << (callback || block) if callback || block
38
- @after_netsuite_pull
52
+ self.netsuite_settings[:after_netsuite_pull] << (callback || block) if callback || block
53
+ self.netsuite_settings[:after_netsuite_pull]
39
54
  end
40
55
 
41
56
  def netsuite_field_map(field_mapping = nil)
42
- if field_mapping.nil?
43
- @netsuite_field_map ||= {}
44
- else
45
- @netsuite_field_map = field_mapping
57
+ if !field_mapping.nil?
58
+ self.netsuite_settings[:netsuite_field_map] = field_mapping
46
59
  end
47
60
 
48
- @netsuite_field_map
49
- end
50
-
51
- def netsuite_local_fields
52
- @netsuite_field_map.except(:custom_field_list).keys + (@netsuite_field_map[:custom_field_list] || {}).keys
61
+ self.netsuite_settings[:netsuite_field_map]
53
62
  end
54
63
 
55
64
  def netsuite_field_hints(list = nil)
56
- if list.nil?
57
- @netsuite_field_hints ||= {}
58
- else
59
- @netsuite_field_hints = list
65
+ if !list.nil?
66
+ self.netsuite_settings[:netsuite_field_hints] = list
60
67
  end
68
+
69
+ self.netsuite_settings[:netsuite_field_hints]
61
70
  end
62
71
 
63
72
  # TODO persist type for CustomRecordRef
64
73
  def netsuite_record_class(record_class = nil, custom_record_type_id = nil)
65
- if record_class.nil?
66
- @netsuite_record_class
67
- else
68
- @netsuite_record_class = record_class
69
- @netsuite_custom_record_type_id = custom_record_type_id
74
+ if !record_class.nil?
75
+ self.netsuite_settings[:netsuite_record_class] = record_class
76
+ self.netsuite_custom_record_type_id = custom_record_type_id
70
77
  end
78
+
79
+ self.netsuite_settings[:netsuite_record_class]
71
80
  end
72
81
 
73
82
  # there is a model level of this method in order to be based on the model level record class
@@ -75,160 +84,153 @@ module NetSuiteRails
75
84
  self.netsuite_record_class == NetSuite::Records::CustomRecord
76
85
  end
77
86
 
78
- # :read_only, :aggressive (push & update on save), :write_only, :read_write
87
+ # :read, :aggressive (push & update on save), :write_only, :read_write
79
88
  def netsuite_sync(flag = nil, opts = {})
80
- if flag.nil?
81
- @netsuite_sync_options ||= {}
82
- @netsuite_sync ||= :read_only
83
- else
84
- @netsuite_sync = flag
85
- @netsuite_sync_options = opts
89
+ if !flag.nil?
90
+ self.netsuite_sync_options = opts
91
+ self.netsuite_settings[:netsuite_sync] = flag
86
92
  end
93
+
94
+ self.netsuite_settings[:netsuite_sync]
87
95
  end
88
96
  end
89
97
 
90
- attr_accessor :netsuite_manual_fields
98
+ module InstanceMethods
99
+ attr_accessor :netsuite_manual_fields
91
100
 
92
- # these methods are here for easy model override
101
+ # these methods are here for easy model override
93
102
 
94
- def netsuite_sync_options
95
- self.class.netsuite_sync_options
96
- end
97
-
98
- def netsuite_sync
99
- self.class.netsuite_sync
100
- end
103
+ def netsuite_sync_options
104
+ self.class.netsuite_sync_options
105
+ end
101
106
 
102
- def netsuite_record_class
103
- self.class.netsuite_record_class
104
- end
107
+ def netsuite_sync
108
+ self.class.netsuite_sync
109
+ end
105
110
 
106
- def netsuite_field_map
107
- self.class.netsuite_field_map
108
- end
111
+ def netsuite_record_class
112
+ self.class.netsuite_record_class
113
+ end
109
114
 
110
- def netsuite_field_hints
111
- self.class.netsuite_field_hints
112
- end
115
+ def netsuite_field_map
116
+ self.class.netsuite_field_map
117
+ end
113
118
 
114
- # assumes netsuite_id field on activerecord
119
+ def netsuite_field_hints
120
+ self.class.netsuite_field_hints
121
+ end
115
122
 
116
- def netsuite_pulling?
117
- @netsuite_pulling ||= false
118
- end
123
+ # assumes netsuite_id field on activerecord
119
124
 
120
- def netsuite_pulled?
121
- @netsuite_pulled ||= false
122
- end
125
+ def netsuite_pulling?
126
+ @netsuite_pulling ||= false
127
+ end
123
128
 
124
- def netsuite_pull
125
- netsuite_extract_from_record(netsuite_pull_record)
126
- end
129
+ def netsuite_pulled?
130
+ @netsuite_pulled ||= false
131
+ end
127
132
 
128
- def netsuite_pull_record
129
- if netsuite_custom_record?
130
- NetSuite::Records::CustomRecord.get(
131
- internal_id: self.netsuite_id,
132
- type_id: self.class.netsuite_custom_record_type_id
133
- )
134
- else
135
- self.netsuite_record_class.get(self.netsuite_id)
133
+ def netsuite_pull
134
+ netsuite_extract_from_record(netsuite_pull_record)
136
135
  end
137
- end
138
136
 
139
- def netsuite_push(opts = {})
140
- NetSuiteRails::RecordSync::PushManager.push(self, opts)
141
- end
137
+ def netsuite_pull_record
138
+ if netsuite_custom_record?
139
+ NetSuite::Records::CustomRecord.get(
140
+ internal_id: self.netsuite_id,
141
+ type_id: self.class.netsuite_custom_record_type_id
142
+ )
143
+ else
144
+ self.netsuite_record_class.get(self.netsuite_id)
145
+ end
146
+ end
142
147
 
143
- def netsuite_extract_from_record(netsuite_record)
144
- @netsuite_pulling = true
148
+ def netsuite_push(opts = {})
149
+ NetSuiteRails::RecordSync::PushManager.push(self, opts)
150
+ end
145
151
 
146
- field_hints = self.netsuite_field_hints
152
+ def netsuite_extract_from_record(netsuite_record)
153
+ @netsuite_pulling = true
147
154
 
148
- custom_field_list = self.netsuite_field_map[:custom_field_list] || {}
155
+ field_hints = self.netsuite_field_hints
149
156
 
150
- all_field_list = self.netsuite_field_map.except(:custom_field_list) || {}
151
- all_field_list.merge!(custom_field_list)
157
+ custom_field_list = self.netsuite_field_map[:custom_field_list] || {}
152
158
 
153
- # self.netsuite_normalize_datetimes(:pull)
159
+ all_field_list = self.netsuite_field_map.except(:custom_field_list) || {}
160
+ all_field_list.merge!(custom_field_list)
154
161
 
155
- # handle non-collection associations
156
- association_keys = self.reflections.values.reject(&:collection?).map(&:name)
162
+ # self.netsuite_normalize_datetimes(:pull)
157
163
 
158
- all_field_list.each do |local_field, netsuite_field|
159
- is_custom_field = custom_field_list.keys.include?(local_field)
164
+ # handle non-collection associations
165
+ association_keys = self.reflections.values.reject(&:collection?).map(&:name)
160
166
 
161
- if netsuite_field.is_a?(Proc)
162
- netsuite_field.call(self, netsuite_record, :pull)
163
- next
164
- end
167
+ all_field_list.each do |local_field, netsuite_field|
168
+ is_custom_field = custom_field_list.keys.include?(local_field)
165
169
 
166
- field_value = if is_custom_field
167
- netsuite_record.custom_field_list.send(netsuite_field).value rescue ""
168
- else
169
- netsuite_record.send(netsuite_field)
170
- end
170
+ if netsuite_field.is_a?(Proc)
171
+ netsuite_field.call(self, netsuite_record, :pull)
172
+ next
173
+ end
171
174
 
172
- if field_value.blank?
173
- # TODO possibly nil out the local value?
174
- next
175
- end
175
+ field_value = if is_custom_field
176
+ netsuite_record.custom_field_list.send(netsuite_field).value rescue ""
177
+ else
178
+ netsuite_record.send(netsuite_field)
179
+ end
176
180
 
177
- if association_keys.include?(local_field)
178
- field_value = self.reflections[local_field].klass.where(netsuite_id: field_value.internal_id).first_or_initialize
179
- elsif is_custom_field
180
- # TODO I believe this only handles a subset of all the possibly CustomField values
181
- if field_value.present? && field_value.is_a?(Hash) && field_value.has_key?(:name)
182
- field_value = field_value[:name]
181
+ if field_value.blank?
182
+ # TODO possibly nil out the local value?
183
+ next
183
184
  end
184
185
 
185
- if field_value.present? && field_value.is_a?(NetSuite::Records::CustomRecordRef)
186
- field_value = field_value.attributes[:name]
186
+ if association_keys.include?(local_field)
187
+ field_value = self.reflections[local_field].klass.where(netsuite_id: field_value.internal_id).first_or_initialize
188
+ elsif is_custom_field
189
+ field_value = NetSuiteRails::RecordSync::PullManager.extract_custom_field_value(field_value)
190
+ else
191
+ # then it's not a custom field
187
192
  end
188
- else
189
- # then it's not a custom field
190
- end
191
193
 
192
- # TODO should we just check for nil? vs present?
194
+ # TODO should we just check for nil? vs present?
193
195
 
194
- # TODO should be moved to Transformations with a direction flag
195
- if field_hints.has_key?(local_field) && field_value.present?
196
- case field_hints[local_field]
197
- when :datetime
198
- field_value = field_value.change(offset: "00:00") - (Time.zone.utc_offset / 3600).hours + (8 + NetSuiteRails::Configuration.netsuite_instance_time_zone_offset).hours
196
+ # TODO should be moved to Transformations with a direction flag
197
+ if field_hints.has_key?(local_field) && field_value.present?
198
+ case field_hints[local_field]
199
+ when :datetime
200
+ field_value = field_value.change(offset: "00:00") - (Time.zone.utc_offset / 3600).hours + (8 + NetSuiteRails::Configuration.netsuite_instance_time_zone_offset).hours
201
+ end
199
202
  end
200
- end
201
203
 
202
- self.send(:"#{local_field}=", field_value)
203
- end
204
+ self.send(:"#{local_field}=", field_value)
205
+ end
204
206
 
205
- netsuite_execute_callbacks(self.class.after_netsuite_pull, netsuite_record)
207
+ netsuite_execute_callbacks(self.class.after_netsuite_pull, netsuite_record)
206
208
 
207
- @netsuite_pulling = false
208
- @netsuite_pulled = true
209
+ @netsuite_pulling = false
210
+ @netsuite_pulled = true
211
+ end
209
212
 
210
- # return netsuite record for debugging
211
- netsuite_record
212
- end
213
213
 
214
- def new_netsuite_record?
215
- self.netsuite_id.blank?
216
- end
214
+ def new_netsuite_record?
215
+ self.netsuite_id.blank?
216
+ end
217
217
 
218
- def netsuite_custom_record?
219
- self.netsuite_record_class == NetSuite::Records::CustomRecord
220
- end
218
+ def netsuite_custom_record?
219
+ self.netsuite_record_class == NetSuite::Records::CustomRecord
220
+ end
221
221
 
222
- # TODO this should be protected; it needs to be pushed down to the Push/Pull manager level
222
+ # TODO this should be protected; it needs to be pushed down to the Push/Pull manager level
223
223
 
224
- def netsuite_execute_callbacks(list, record)
225
- list.each do |callback|
226
- if callback.is_a?(Symbol)
227
- self.send(callback, record)
228
- else
229
- instance_exec(record, &callback)
224
+ def netsuite_execute_callbacks(list, record)
225
+ list.each do |callback|
226
+ if callback.is_a?(Symbol)
227
+ self.send(callback, record)
228
+ else
229
+ instance_exec(record, &callback)
230
+ end
230
231
  end
231
232
  end
233
+
232
234
  end
233
235
 
234
236
  end
@@ -10,15 +10,26 @@ module NetSuiteRails::TestHelpers
10
10
  if stamp.nil?
11
11
  @netsuite_timestamp ||= (Time.now - (60 * 2)).to_datetime
12
12
  else
13
- @netsuite_timestamp ||= stamp
13
+ @netsuite_timestamp = stamp
14
14
  end
15
15
  end
16
16
 
17
17
  def get_last_netsuite_object(record)
18
- search = record.netsuite_record_class.search({
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({
19
29
  criteria: {
20
30
  basic:
21
- if record.netsuite_custom_record?
31
+ (
32
+ if is_custom_record
22
33
  [
23
34
  {
24
35
  field: 'recType',
@@ -39,18 +50,35 @@ module NetSuiteRails::TestHelpers
39
50
  value: netsuite_timestamp
40
51
  }
41
52
  ]
53
+ end +
54
+
55
+ if record_class == NetSuite::Records::SalesOrder
56
+ [
57
+ {
58
+ field: 'type',
59
+ operator: 'anyOf',
60
+ value: [ '_salesOrder' ]
61
+ }
62
+ ]
63
+ else
64
+ []
42
65
  end
66
+ )
43
67
  }
44
68
  })
45
69
 
46
- if record.netsuite_custom_record?
70
+ if is_custom_record
47
71
  NetSuite::Records::CustomRecord.get(
48
72
  internal_id: search.results.first.internal_id.to_i,
49
73
  type_id: record.class.netsuite_custom_record_type_id
50
74
  )
51
75
  else
52
- record.netsuite_record_class.get(search.results.first.internal_id.to_i)
76
+ record_class.get(search.results.first.internal_id.to_i)
53
77
  end
54
78
  end
55
79
 
56
- end
80
+ end
81
+
82
+ RSpec.configure do |config|
83
+ config.include NetSuiteRails::TestHelpers, type: :feature
84
+ end