Class: ZohoApi::Crm

Inherits:
Object
  • Object
show all
Includes:
HTTMultiParty, ZohoApiFieldUtils, ZohoApiFinders
Defined in:
lib/zoho_api.rb

Constant Summary

Constants included from ZohoApiFinders

ZohoApiFinders::NUMBER_OF_RECORDS_TO_GET

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ZohoApiFinders

#find_record_by_field, #find_record_by_id, #find_record_by_related_id, #find_records

Methods included from ZohoApiFieldUtils

#add_field, #adjust_tag_case, #clean_field_name?, #create_and_add_field_value_pair, #extract_field, #extract_fields_from_response, #fields, #fields_from_api, #fields_from_record, #fields_original, #hashed_field_value_pairs, #reflect_module_fields, #to_hash, #to_hash_with_id, #update_module_fields, #user_fields

Constructor Details

#initialize(auth_token, modules, ignore_fields, fields = nil) ⇒ Crm

Returns a new instance of Crm.



29
30
31
32
33
34
# File 'lib/zoho_api.rb', line 29

def initialize(auth_token, modules, ignore_fields, fields = nil)
  @auth_token = auth_token
  @modules = %w(Accounts Contacts Events Leads Potentials Tasks Users).concat(modules).uniq
  @module_fields = fields.nil? ? reflect_module_fields : fields
  @ignore_fields = ignore_fields
end

Instance Attribute Details

#auth_tokenObject (readonly)

debug_output $stderr



27
28
29
# File 'lib/zoho_api.rb', line 27

def auth_token
  @auth_token
end

#module_fieldsObject (readonly)

debug_output $stderr



27
28
29
# File 'lib/zoho_api.rb', line 27

def module_fields
  @module_fields
end

Instance Method Details

#add_record(module_name, fields_values_hash) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/zoho_api.rb', line 36

def add_record(module_name, fields_values_hash)
  x = REXML::Document.new
  element = x.add_element module_name
  row = element.add_element 'row', { 'no' => '1' }
  fields_values_hash.each_pair { |k, v| add_field(row, ApiUtils.symbol_to_string(k), v) }
  r = self.class.post(create_url(module_name, 'insertRecords'),
                      :query => { :newFormat => 1, :authtoken => @auth_token,
                                  :scope => 'crmapi', :xmlData => x },
                      :headers => { 'Content-length' => '0' })
  check_for_errors(r)
  x_r = REXML::Document.new(r.body).elements.to_a('//recorddetail')
  to_hash(x_r, module_name)[0]
end

#attach_file(module_name, record_id, file_path, file_name) ⇒ Object

Raises:

  • (RuntimeError)


50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/zoho_api.rb', line 50

def attach_file(module_name, record_id, file_path, file_name)
  mime_type = (MIME::Types.type_for(file_path)[0] || MIME::Types['application/octet-stream'][0])
  url_path = create_url(module_name, "uploadFile?authtoken=#{@auth_token}&scope=crmapi&id=#{record_id}")
  url = URI.parse(create_url(module_name, url_path))
  io = UploadIO.new(file_path, mime_type, file_name)
  req = Net::HTTP::Post::Multipart.new url_path, 'content' => io
  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  res = http.start do |h|
    h.request(req)
  end
  raise(RuntimeError, "[RubyZoho] Attach of file #{file_path} to module #{module_name} failed.") unless res.code == '200'
  res.code
end

#check_for_errors(response) ⇒ Object

Raises:

  • (RuntimeError)


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/zoho_api.rb', line 65

def check_for_errors(response)
  raise(RuntimeError, "Web service call failed with #{response.code}") unless response.code == 200
  x = REXML::Document.new(response.body)

  # updateRelatedRecords returns two codes one in the status tag and another in a success tag, we want the
  # code under the success tag in this case
  code = REXML::XPath.first(x, '//success/code') || code = REXML::XPath.first(x, '//code')

  # 4422 code is no records returned, not really an error
  # TODO: find out what 5000 is
  # 4800 code is returned when building an association. i.e Adding a product to a lead. Also this doesn't return a message
  raise(RuntimeError, "Zoho Error Code #{code.text}: #{REXML::XPath.first(x, '//message').text}.") unless code.nil? || ['4422', '5000', '4800'].index(code.text)

  return code.text unless code.nil?
  response.code
end

#create_url(module_name, api_call) ⇒ Object



82
83
84
# File 'lib/zoho_api.rb', line 82

def create_url(module_name, api_call)
  "https://crm.zoho.com/crm/private/xml/#{module_name}/#{api_call}"
end

#delete_record(module_name, record_id) ⇒ Object



86
87
88
# File 'lib/zoho_api.rb', line 86

def delete_record(module_name, record_id)
  post_action(module_name, record_id, 'deleteRecords')
end

#extract_user_name_and_attribs(node) ⇒ Object



202
203
204
205
206
207
208
209
# File 'lib/zoho_api.rb', line 202

def extract_user_name_and_attribs(node)
  record = {}
  record.merge!({ :user_name => node.text })
  node.attributes.each_pair do |k, v|
    record.merge!({ k.to_s.to_sym => v.to_string.match(/'(.*?)'/).to_s.gsub('\'', '') })
  end
  record
end

#extract_users_from_xml_response(response) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
# File 'lib/zoho_api.rb', line 190

def extract_users_from_xml_response(response)
  x = REXML::Document.new(response.body).elements.to_a('/users')
  result = []
  x.each do |e|
    e.elements.to_a.each do |node|
      record = extract_user_name_and_attribs(node)
      result << record
    end
  end
  result
end

#first(module_name) ⇒ Object



90
91
92
# File 'lib/zoho_api.rb', line 90

def first(module_name)
  some(module_name, 1, 1)
end

#method_name?(n) ⇒ Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/zoho_api.rb', line 94

def method_name?(n)
  return /[@$"]/ !~ n.inspect
end

#post_action(module_name, record_id, action_type) ⇒ Object

Raises:

  • ('Adding contact failed')


98
99
100
101
102
103
104
105
# File 'lib/zoho_api.rb', line 98

def post_action(module_name, record_id, action_type)
  r = self.class.post(create_url(module_name, action_type),
                      :query => { :newFormat => 1, :authtoken => @auth_token,
                                  :scope => 'crmapi', :id => record_id },
                      :headers => { 'Content-length' => '0' })
  raise('Adding contact failed', RuntimeError, r.response.body.to_s) unless r.response.code == '200'
  check_for_errors(r)
end

#primary_key(module_name) ⇒ Object



107
108
109
110
111
# File 'lib/zoho_api.rb', line 107

def primary_key(module_name)
  activity_keys = { 'Tasks' => :activityid, 'Events' => :activityid, 'Calls' => :activityid }
  return activity_keys[module_name] unless activity_keys[module_name].nil?
  (module_name.downcase.chop + 'id').to_sym
end

#primary_key?(module_name, field_name) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
117
118
119
# File 'lib/zoho_api.rb', line 113

def primary_key?(module_name, field_name)
  return nil if field_name.nil? || module_name.nil?
  fn = field_name.class == String ? field_name : field_name.to_s
  return true if fn == 'id'
  return true if %w[Calls Events Tasks].index(module_name) && fn.downcase == 'activityid'
  fn.downcase.gsub('id', '') == module_name.chop.downcase
end

Returns:

  • (Boolean)


121
122
123
124
125
126
# File 'lib/zoho_api.rb', line 121

def related_id?(module_name, field_name)
  field = field_name.to_s
  return false if field.rindex('id').nil?
  return false if %w[Calls Events Tasks].index(module_name) && field_name.downcase == 'activityid'
  field.downcase.gsub('id', '') != module_name.chop.downcase
end


128
129
130
131
132
133
134
135
# File 'lib/zoho_api.rb', line 128

def related_records(parent_module, parent_record_id, related_module)
  r = self.class.get(create_url("#{related_module}", 'getRelatedRecords'),
                     :query => { :newFormat => 1, :authtoken => @auth_token, :scope => 'crmapi',
                                 :parentModule => parent_module, :id => parent_record_id })

  x = REXML::Document.new(r.body).elements.to_a("/response/result/#{parent_module}/row")
  check_for_errors(r)
end

#some(module_name, index = 1, number_of_records = nil, sort_column = :id, sort_order = :asc) ⇒ Object



137
138
139
140
141
142
143
144
145
146
# File 'lib/zoho_api.rb', line 137

def some(module_name, index = 1, number_of_records = nil, sort_column = :id, sort_order = :asc)
  r = self.class.get(create_url(module_name, 'getRecords'),
                     :query => { :newFormat => 2, :authtoken => @auth_token, :scope => 'crmapi',
                                 :sortColumnString => sort_column, :sortOrderString => sort_order,
                                 :fromIndex => index, :toIndex => number_of_records || NUMBER_OF_RECORDS_TO_GET })
  return nil unless r.response.code == '200'
  check_for_errors(r)
  x = REXML::Document.new(r.body).elements.to_a("/response/result/#{module_name}/row")
  to_hash(x, module_name)
end

#update_record(module_name, id, fields_values_hash) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/zoho_api.rb', line 165

def update_record(module_name, id, fields_values_hash)
  x = REXML::Document.new
  contacts = x.add_element module_name
  row = contacts.add_element 'row', { 'no' => '1' }
  fields_values_hash.each_pair { |k, v| add_field(row, ApiUtils.symbol_to_string(k), v) }
  r = self.class.post(create_url(module_name, 'updateRecords'),
                      :query => { :newFormat => 1, :authtoken => @auth_token,
                                  :scope => 'crmapi', :id => id,
                                  :xmlData => x },
                      :headers => { 'Content-length' => '0' })
  check_for_errors(r)
  x_r = REXML::Document.new(r.body).elements.to_a('//recorddetail')
  to_hash_with_id(x_r, module_name)[0]
end


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

def update_related_records(parent_module, parent_record_id, related_module_fields)
  x = REXML::Document.new
  leads = x.add_element related_module_fields[:related_module]
  row = leads.add_element 'row', { 'no' => '1' }
  related_module_fields[:xml_data].each_pair { |k, v| add_field(row, ApiUtils.symbol_to_string(k), v) }
  
  r = self.class.post(create_url("#{parent_module}", 'updateRelatedRecords'),
                      :query => { :newFormat => 1,
                                  :id => parent_record_id,
                                  :authtoken => @auth_token, :scope => 'crmapi',
                                  :relatedModule => related_module_fields[:related_module],
                                  :xmlData => x },
                      :headers => { 'Content-length' => '0' })

  check_for_errors(r)
end

#users(user_type = 'AllUsers') ⇒ Object



180
181
182
183
184
185
186
187
188
# File 'lib/zoho_api.rb', line 180

def users(user_type = 'AllUsers')
  return @@users unless @@users == [] || user_type == 'Refresh'
  r = self.class.get(create_url('Users', 'getUsers'),
                     :query => { :newFormat => 1, :authtoken => @auth_token, :scope => 'crmapi',
                                 :type => 'AllUsers' })
  check_for_errors(r)
  result = extract_users_from_xml_response(r)
  @@users = result
end

#valid_related?(module_name, field) ⇒ Boolean

Returns:

  • (Boolean)


211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/zoho_api.rb', line 211

def valid_related?(module_name, field)
  return nil if field.downcase == 'smownerid'
  valid_relationships = {
      'Leads' => %w(email),
      'Accounts' => %w(accountid accountname),
      'Contacts' => %w(contactid accountid vendorid email),
      'Potentials' => %w(potentialid accountid campaignid contactid potentialname),
      'Campaigns' => %w(campaignid campaignname),
      'Cases' => %w(caseid productid accountid potentialid),
      'Solutions' => %w(solutionid productid),
      'Products' => %w(productid vendorid productname),
      'Purchase Order' => %w(purchaseorderid contactid vendorid),
      'Quotes' => %w(quoteid potentialid accountid contactid),
      'Sales Orders' => %w(salesorderid potentialid accountid contactid quoteid),
      'Invoices' => %w(invoiceid accountid salesorderid contactid),
      'Vendors' => %w(vendorid vendorname),
      'Tasks' => %w(taskid),
      'Events' => %w(eventid),
      'Notes' => %w(notesid)
  }
  valid_relationships[module_name].index(field.downcase)
end