Module: SalesforceArSync::SalesforceSync

Extended by:
ActiveSupport::Concern
Defined in:
lib/salesforce_ar_sync/salesforce_sync.rb

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#salesforce_skip_syncObject

if this instance variable is set to true, the salesforce_sync method will return without attempting to sync data to Salesforce



79
80
81
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 79

def salesforce_skip_sync
  @salesforce_skip_sync
end

Instance Method Details

#ar_sync_inbound_delete?Boolean

Check to see if the user passed in a true/false, if so return that, if not then they passed int a symbol to a method We then call the method and use its value instead

Returns:

  • (Boolean)


189
190
191
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 189

def ar_sync_inbound_delete?
  [true,false].include?(self.class.sync_inbound_delete) ? self.class.sync_inbound_delete : send(self.class.sync_inbound_delete)
end

#ar_sync_outbound_delete?Boolean

Returns:

  • (Boolean)


193
194
195
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 193

def ar_sync_outbound_delete?
  [true,false].include?(self.class.sync_outbound_delete) ? self.class.sync_outbound_delete : send(self.class.sync_outbound_delete)
end

#get_activerecord_web_idObject



226
227
228
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 226

def get_activerecord_web_id
  self.send(self.class.activerecord_web_id_attribute_name)
end

#is_boolean?(attribute) ⇒ Boolean

Returns:

  • (Boolean)


165
166
167
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 165

def is_boolean?(attribute)
  self.column_for_attribute(attribute) && self.column_for_attribute(attribute).type == :boolean
end

#salesforce_attributes_to_set(attributes = {}) ⇒ Object

An internal method used to get a hash of values that we are going to set from a Salesforce outbound message hash



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 92

def salesforce_attributes_to_set(attributes = {})
  {}.tap do |hash|
    # loop through the hash of attributes from the outbound message, and compare to our sf mappings and
    # create a reversed hash of value's and key's to pass to update_attributes
    attributes.each do |key, value|
      # make sure our sync_mapping contains the salesforce attribute AND that our object has a setter for it
      hash[self.class.salesforce_sync_attribute_mapping[key.to_s].to_sym] = value if self.class.salesforce_sync_attribute_mapping.include?(key.to_s) && self.respond_to?("#{self.class.salesforce_sync_attribute_mapping[key.to_s]}=")
    end

    # remove the web_id from hash if it exists, as we don't want to modify a web_id
    hash.delete(:id) if hash[:id]

    # update the sf_updated_at field with the system mod stamp from sf
    hash[:salesforce_updated_at] = attributes[:SystemModstamp]

    # incase we looked up via the WebId__c, we should set the salesforce_id
    hash[:salesforce_id] = attributes[self.class.salesforce_id_attribute_name]
  end
end

#salesforce_attributes_to_update(include_all = false) ⇒ Object

create a hash of updates to send to salesforce



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 148

def salesforce_attributes_to_update(include_all = false)
  {}.tap do |hash|
    self.class.salesforce_sync_attribute_mapping.each do |key, value|
      if self.respond_to?(value)

        #Checkboxes in SFDC Cannot be nil.  Here we check for boolean field type and set nil values to be false
        attribute_value = self.send(value)
        if is_boolean?(value) && attribute_value.nil?
          attribute_value = false
        end

        hash[key] = attribute_value if include_all || salesforce_should_update_attribute?(value)
      end
    end
  end
end

#salesforce_create_object(attributes) ⇒ Object



169
170
171
172
173
174
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 169

def salesforce_create_object(attributes)
  attributes.merge!(self.class.salesforce_web_id_attribute_name.to_s => id) if self.class.salesforce_sync_web_id? && !new_record?
  result = SF_CLIENT.http_post("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}", format_attributes(attributes).to_json)
  self.salesforce_id = JSON.parse(result.body)["id"]
  @exists_in_salesforce = true
end

#salesforce_delete_objectObject



181
182
183
184
185
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 181

def salesforce_delete_object
  if self.ar_sync_outbound_delete?
    SF_CLIENT.http_delete("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}/#{salesforce_id}")
  end
end

#salesforce_empty_attributesObject

Salesforce completely excludes any empty/null fields from Outbound Messages We initialize all declared attributes as nil before mapping the values from the message



83
84
85
86
87
88
89
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 83

def salesforce_empty_attributes
  {}.tap do |hash|
    self.class.salesforce_sync_attribute_mapping.each do |key, value|
      hash[key] = nil
    end
  end
end

#salesforce_object_exists?Boolean

Returns:

  • (Boolean)


137
138
139
140
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 137

def salesforce_object_exists?
  return @exists_in_salesforce if @exists_in_salesforce
  @exists_in_salesforce = !system_mod_stamp.nil?
end

#salesforce_perform_async_call?Boolean

if attributes specified in the async_attributes array are the only attributes being modified, then sync the data via delayed_job

Returns:

  • (Boolean)


199
200
201
202
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 199

def salesforce_perform_async_call?
  return false if salesforce_attributes_to_update.empty? || self.class.salesforce_async_attributes.empty?
  salesforce_attributes_to_update.keys.all? {|key| self.class.salesforce_async_attributes.include?(key) } && salesforce_id.present?
end

#salesforce_process_update(attributes = {}) ⇒ Object

Gets passed the Salesforce outbound message hash of changed values and updates the corresponding model



113
114
115
116
117
118
119
120
121
122
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 113

def salesforce_process_update(attributes = {})
  attributes_to_update = salesforce_attributes_to_set(self.new_record? ? attributes : salesforce_empty_attributes.merge(attributes)) # only merge empty attributes for updates, so we don't overwrite the default create attributes
  attributes_to_update.each_pair do |k, v|
    self.send("#{k}=", v)
  end

  # we don't want to keep going in a endless loop.  SF has just updated these values.
  self.salesforce_skip_sync = true
  self.save!
end

#salesforce_should_update_attribute?(attribute) ⇒ Boolean

Checks if the passed in attribute should be updated in Salesforce.com

Returns:

  • (Boolean)


143
144
145
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 143

def salesforce_should_update_attribute?(attribute)
  !self.respond_to?("#{attribute}_changed?") || (self.respond_to?("#{attribute}_changed?") && self.send("#{attribute}_changed?"))
end

#salesforce_syncObject

sync model data to Salesforce, adding any Salesforce validation errors to the models errors



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 205

def salesforce_sync
  return if self.salesforce_skip_sync?
  if salesforce_perform_async_call?
    Delayed::Job.enqueue(SalesforceArSync::SalesforceObjectSync.new(self.class.salesforce_web_class_name, salesforce_id, salesforce_attributes_to_update), :priority => 50)
  else
    if salesforce_object_exists?
      salesforce_update_object(salesforce_attributes_to_update) if salesforce_attributes_to_update.present?
    else
      salesforce_create_object(salesforce_attributes_to_update(!new_record?)) if salesforce_id.nil?
    end
  end
rescue Exception => ex
  self.errors[:base] << ex.message
  return false
end

#salesforce_update_object(attributes) ⇒ Object



176
177
178
179
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 176

def salesforce_update_object(attributes)
  attributes.merge!(self.class.salesforce_web_id_attribute_name.to_s => id) if self.class.salesforce_sync_web_id? && !new_record?
  SF_CLIENT.http_patch("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}/#{salesforce_id}", format_attributes(attributes).to_json)
end

#sync_web_idObject



221
222
223
224
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 221

def sync_web_id
  return false if !self.class.salesforce_sync_web_id? || self.salesforce_skip_sync?
  SF_CLIENT.http_patch("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}/#{salesforce_id}", { self.class.salesforce_web_id_attribute_name.to_s => get_activerecord_web_id }.to_json) if salesforce_id
end

#system_mod_stampObject

Finds a salesforce record by its Id and returns nil or its SystemModstamp



131
132
133
134
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 131

def system_mod_stamp
  hash = JSON.parse(SF_CLIENT.http_get("/services/data/v#{SF_CLIENT.version}/query", :q => "SELECT SystemModstamp FROM #{salesforce_object_name} WHERE Id = '#{salesforce_id}'").body)
  hash["records"].first.try(:[], "SystemModstamp")
end