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



70
71
72
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 70

def salesforce_skip_sync
  @salesforce_skip_sync
end

Instance Method Details

#is_boolean?(attribute) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 156

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



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 83

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



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 139

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



160
161
162
163
164
165
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 160

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}", attributes.to_json)
  self.salesforce_id = JSON.parse(result.body)["id"]
  @exists_in_salesforce = true
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



74
75
76
77
78
79
80
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 74

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)


128
129
130
131
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 128

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)


174
175
176
177
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 174

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



104
105
106
107
108
109
110
111
112
113
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 104

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)


134
135
136
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 134

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



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 180

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



167
168
169
170
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 167

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}", attributes.to_json)
end

#sync_web_idObject



196
197
198
199
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 196

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 => id }.to_json) if salesforce_id
end

#system_mod_stampObject

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



122
123
124
125
# File 'lib/salesforce_ar_sync/salesforce_sync.rb', line 122

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