Class: NetSuiteRails::RecordSync::PushManager
- Inherits:
-
Object
- Object
- NetSuiteRails::RecordSync::PushManager
- Defined in:
- lib/netsuite_rails/record_sync/push_manager.rb
Class Method Summary collapse
- .all_netsuite_fields(local_record) ⇒ Object
- .build_netsuite_record(local_record, opts = {}) ⇒ Object
- .build_netsuite_record_reference(local_record, opts = {}) ⇒ Object
- .changed_attributes(local_record) ⇒ Object
- .is_active_record_model?(local_record) ⇒ Boolean
- .modified_local_fields(local_record) ⇒ Object
- .push(local_record, opts = {}) ⇒ Object
- .push_add(local_record, netsuite_record, opts = {}) ⇒ Object
- .push_update(local_record, netsuite_record, opts = {}) ⇒ Object
- .relationship_attributes_list(local_record) ⇒ Object
Class Method Details
.all_netsuite_fields(local_record) ⇒ Object
195 196 197 198 199 200 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 195 def all_netsuite_fields(local_record) custom_netsuite_field_list = local_record.netsuite_field_map[:custom_field_list] || {} standard_netsuite_field_list = local_record.netsuite_field_map.except(:custom_field_list) || {} custom_netsuite_field_list.merge(standard_netsuite_field_list) end |
.build_netsuite_record(local_record, opts = {}) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 114 def build_netsuite_record(local_record, opts = {}) netsuite_record = build_netsuite_record_reference(local_record, opts) all_field_list = opts[:modified_fields] custom_field_list = local_record.netsuite_field_map[:custom_field_list] || {} field_hints = local_record.netsuite_field_hints reflections = relationship_attributes_list(local_record) all_field_list.each do |local_field, netsuite_field| # allow Procs as field mapping in the record definition for custom mapping if netsuite_field.is_a?(Proc) netsuite_field.call(local_record, netsuite_record, :push) next end # TODO pretty sure this will break if we are dealing with has_many netsuite_field_value = if reflections.has_key?(local_field) if (remote_internal_id = local_record.send(local_field).try(:netsuite_id)).present? { internal_id: remote_internal_id } else nil end else local_record.send(local_field) end if field_hints.has_key?(local_field) && netsuite_field_value.present? netsuite_field_value = NetSuiteRails::Transformations.transform(field_hints[local_field], netsuite_field_value, :push) end # TODO should we skip setting nil values completely? What if we want to nil out fields on update? # be wary of API version issues: https://github.com/NetSweet/netsuite/issues/61 if custom_field_list.keys.include?(local_field) netsuite_record.custom_field_list.send(:"#{netsuite_field}=", netsuite_field_value) else netsuite_record.send(:"#{netsuite_field}=", netsuite_field_value) end end netsuite_record end |
.build_netsuite_record_reference(local_record, opts = {}) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 160 def build_netsuite_record_reference(local_record, opts = {}) # must set internal_id for records on new; will be set to nil if new record init_hash = if opts[:use_external_id] { external_id: local_record.netsuite_external_id } else { internal_id: local_record.netsuite_id } end netsuite_record = local_record.netsuite_record_class.new(init_hash) if local_record.netsuite_custom_record? netsuite_record.rec_type = NetSuite::Records::CustomRecord.new(internal_id: local_record.class.netsuite_custom_record_type_id) end netsuite_record end |
.changed_attributes(local_record) ⇒ Object
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 202 def changed_attributes(local_record) # otherwise filter only by attributes that have been changed # limiting the delta sent to NS will reduce hitting edge cases # TODO think about has_many / join table changes reflections = relationship_attributes_list(local_record) association_field_key_mapping = reflections.values.reject(&:collection?).inject({}) do |h, a| begin h[a.association_foreign_key.to_sym] = a.name rescue Exception => e # occurs when `has_one through:` exists on a record but `through` is not a valid reference Rails.logger.error "NetSuite: error detecting foreign key #{a.name}" end h end changed_attributes_keys = local_record.changed_attributes.keys serialized_attrs = if NetSuiteRails.rails4? local_record.class.serialized_attributes else local_record.serialized_attributes end # changes_attributes does not track serialized attributes, although it does track the storage key # if a serialized attribute storage key is dirty assume that all keys in the hash are dirty as well changed_attributes_keys += serialized_attrs.keys.map do |k| local_record.send(k.to_sym).keys.map(&:to_s) end.flatten # convert relationship symbols from :object_id to :object changed_attributes_keys.map do |k| association_field_key_mapping[k.to_sym] || k.to_sym end end |
.is_active_record_model?(local_record) ⇒ Boolean
254 255 256 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 254 def is_active_record_model?(local_record) defined?(::ActiveRecord::Base) && local_record.class.ancestors.include?(ActiveRecord::Base) end |
.modified_local_fields(local_record) ⇒ Object
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 178 def modified_local_fields(local_record) synced_netsuite_fields = all_netsuite_fields(local_record) changed_keys = if is_active_record_model?(local_record) changed_attributes(local_record) else local_record.changed_attributes end # filter out unchanged keys when updating record unless local_record.new_netsuite_record? synced_netsuite_fields.select! { |k,v| changed_keys.include?(k) } end synced_netsuite_fields end |
.push(local_record, opts = {}) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 7 def push(local_record, opts = {}) # TODO check to see if anything is changed before moving forward # if changes_keys.blank? && local_record.netsuite_manual_fields # always include the full netsuite field mapping, regardless of which # fields were modfified locally, when initially creating the netsuite record if opts[:modified_fields] && !local_record.new_netsuite_record? # if Array, we need to convert info fields hash based on the record definition if opts[:modified_fields].is_a?(Array) opts[:modified_fields] = all_netsuite_fields(local_record).select { |k,v| opts[:modified_fields].include?(k) } end else opts[:modified_fields] = modified_local_fields(local_record) end netsuite_record = build_netsuite_record(local_record, opts) local_record.netsuite_execute_callbacks(local_record.class.before_netsuite_push, netsuite_record) if opts[:push_method] == :upsert || local_record.new_netsuite_record? push_add(local_record, netsuite_record, opts) else push_update(local_record, netsuite_record, opts) end local_record.netsuite_execute_callbacks(local_record.class.after_netsuite_push, netsuite_record) true end |
.push_add(local_record, netsuite_record, opts = {}) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 38 def push_add(local_record, netsuite_record, opts = {}) # push_method is either :add or :upsert if netsuite_record.send(opts[:push_method] || :add) Rails.logger.info "NetSuite: action=#{opts[:push_method]}, local_record=#{local_record.class}[#{local_record.id}]" + "netsuite_record_type=#{netsuite_record.class}, netsuite_record_id=#{netsuite_record.internal_id}" if is_active_record_model?(local_record) # update_column to avoid triggering another save local_record.update_column(:netsuite_id, netsuite_record.internal_id) else netsuite_record.internal_id end else raise "NetSuite: error. action=#{opts[:push_method]}, netsuite_record_type=#{netsuite_record.class}, errors=#{netsuite_record.errors}" end end |
.push_update(local_record, netsuite_record, opts = {}) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 55 def push_update(local_record, netsuite_record, opts = {}) # build change hash to limit the number of fields pushed to NS on change # NS could have logic which could change field functionality depending on # input data; it's safest to limit the number of field changes pushed to NS # exclude fields that map to procs: they don't indicate which netsuite field # the local rails field maps to, so the user must specify this manually in `netsuite_manual_fields` # TODO add option for model to mark `custom_field_list = true` if custom field mapping to a # proc is detected. This is helpful for users mapping a local field to a custom field custom_field_list = local_record.netsuite_field_map[:custom_field_list] || {} custom_field_list = custom_field_list.select { |local_field, netsuite_field| !netsuite_field.is_a?(Proc) } modified_fields_list = opts[:modified_fields] modified_fields_list = modified_fields_list.select { |local_field, netsuite_field| !netsuite_field.is_a?(Proc) } update_list = {} modified_fields_list.each do |local_field, netsuite_field| if custom_field_list.keys.include?(local_field) # if custom field has changed, mark and copy over customFieldList later update_list[:custom_field_list] = true else update_list[netsuite_field] = netsuite_record.send(netsuite_field) end end # manual field list is for fields manually defined on the NS record # outside the context of ActiveRecord (e.g. in a before_netsuite_push) (local_record.netsuite_manual_fields || []).each do |netsuite_field| if netsuite_field == :custom_field_list update_list[:custom_field_list] = true else update_list[netsuite_field] = netsuite_record.send(netsuite_field) end end if update_list[:custom_field_list] update_list[:custom_field_list] = netsuite_record.custom_field_list end if local_record.netsuite_custom_record? update_list[:rec_type] = netsuite_record.rec_type end Rails.logger.info "NetSuite: Update #{netsuite_record.class} #{netsuite_record.internal_id}, list #{update_list.keys}" # don't update if list is empty return if update_list.empty? if netsuite_record.update(update_list) true else raise "NetSuite: error updating record #{netsuite_record.errors}" end end |
.relationship_attributes_list(local_record) ⇒ Object
242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/netsuite_rails/record_sync/push_manager.rb', line 242 def relationship_attributes_list(local_record) if is_active_record_model?(local_record) if NetSuiteRails.rails4? local_record.class.reflections else local_record.reflections end else local_record.respond_to?(:reflections) ? local_record.reflections : {} end end |