Connect to Zoho CRM with Ruby

By Jimmy Bonney | June 3, 2012

Zoho

At D-Sight, we use Zoho CRM to follow-up on our leads (people who try out D-Sight or D-Sight Web). Being able to integrate Zoho solutions with our products makes it easier for us to focus on important activities, rather than spending time importing contacts manually from our applications.

The problem is that Zoho documentation is rather sparse on technical details about Ruby integration. Quite a lot of things are available for PHP and Java users but for the moment it seems that Ruby is not a top priority. However, Zoho offers a great API and therefore integration with Ruby is not that complicated.

We have therefore created a script that reads in a MySQL database, extracts the latest entries and sends them to Zoho. In case any error occur while sending the data to Zoho, an email containing the entries that could not be added is sent out to the administrator.

The project is divided in three files: a Gemfile, containing the necessary gems used by the script, the script itself generic_zoho_import.rb, and a file containing historical information about when the script is executed history.csv. Everything is available on BitBucket.

In order to use the script for your own needs, a few changes need to take place. Everything is marked with a comment [UPDATE WITH YOUR VALUES]. The biggest change is probably around the structure of your DB and the different models that you use. In addition, the version below might not be the latest one available so it is better to download it from the repository.

1
2
3
4
5
6
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
113
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
#!/usr/bin/ruby

# Import users from a MySQL DB to Zoho CRM
# @author: Jimmy Bonney (jbonney@d-sight.com)
# @created_at: 2012-05-14
# @sponsor: D-Sight (http://www.d-sight.com)
# @version: 1.0

# Dependencies
require 'rubygems'
require 'active_record'
require 'httparty'
require 'csv'
require 'mail'

# [UPDATE WITH YOUR VALUES]
# Email setup
Mail.defaults do
    delivery_method :smtp, {
        :address              => 'mail.yourcompany.com',
        :port                 => 25,
        :domain               => "yourcompany.com",
        :user_name            => 'user',
        :password             => 'abcdefgh',
        :authentication       => 'plain',
        :enable_starttls_auto => false }
end

# [UPDATE WITH YOUR VALUES]
# Set up active record connection
ActiveRecord::Base.establish_connection(
    :adapter => "mysql2",
    :encoding => "utf8",
    :database => "database_name",
    :username => "database_user",
    :password => "abcdefgh",
    :host => "localhost",
    :timeout => 5000
)

# [UPDATE WITH YOUR MODELS AS DEFINED IN YOUR APPLICATION]
# Client Accounts
class Account < ActiveRecord::Base
end

# Users
class User < ActiveRecord::Base
end

# Roles
class Role < ActiveRecord::Base
end

# User Roles
class UserRoleMapping < ActiveRecord::Base
end

# Define class to connect to Zoho CRM API
class ZohoCRM
    include HTTParty
end

# Script directory
path = File.expand_path(File.dirname(__FILE__))
# Get the historical data
previous_executions = CSV.read(path + "/history.csv", :headers => :true)
# Get the last execution data
last_execution = previous_executions[previous_executions.size-1]
# Get the last execution date (this is the first column)
last_date = DateTime.parse last_execution['Last Execution Time']
puts "Last execution date: "
puts last_date

# Set the new execution date (now)
new_date = DateTime.now
# Set the date format used in file name
date_info = new_date.strftime("%Y%m%d")

# Get the accounts created during the period [last_date, new_date]
accounts = Account.where("created_at > ? and created_at < ?", last_date, new_date - 1.seconds).all
puts "Number of accounts created since last time: "
puts accounts.count

# Save how many accounts are correctly sent to Zoho
successfully_saved = 0
# Prepare hash to save any errors than would occur
errors = Hash.new

# [UPDATE WITH YOUR MODEL STRUCTURE]
# Go through the accounts list
accounts.each do |account|
    owner = Role.where("name = ? and authorizable_id = ?", 'owner', account.id).first
    user_role_id = UserRoleMapping.where("role_id = ?", owner.id).first.user_id
    user = User.where("id = ?", user_role_id).first
    puts "User email: "
    puts user.email

    # Prepare data to be sent to Zoho
    xml_data = "<Leads><row no=\"1\"><FL val=\"Lead Source\">Your Web Application</FL><FL val=\"First Name\">#{user.first_name}</FL><FL val=\"Last Name\">#{user.last_name}</FL><FL val=\"Email\">#{user.email}</FL></row></Leads>"

    # [UPDATE WITH YOUR Authentication Token]
    puts "Sending user data to Zoho"
    response = ZohoCRM.post('https://crm.zoho.com/crm/private/xml/Leads/insertRecords', :body => {:newFormat => '1', :authtoken => '[YOUR_AUTH_TOKEN]', :scope => 'crmapi', :xmlData => xml_data})

    # Register success or failure
    if response.code < 300
        puts "User added successfully to Zoho"
        successfully_saved += 1
    else
        puts "An error occured while adding user"
        errors[account.id] = response.parsed_response["response"]["error"]
        # Add entry that would not have been sent to Zoho in a CSV file
        CSV.open(path + "/" + date_info + "_manual_import.csv", "a") do |csv|
            csv << ['Date', 'Account ID', 'Email', 'First Name', 'Last Name'] if errors.size == 1
            csv << [new_date, account.id, user.email, user.first_name, user.last_name]
        end
    end
end

# Save history
CSV.open(path + "/history.csv", "a") do |csv|
    csv << [new_date, accounts.count, successfully_saved]
end

puts "History updated"

# [UPDATE WITH YOUR VALUES]
# Send email in case of failure
if successfully_saved != accounts.count
    puts "Sending email to inform administrator that manual import to Zoho is required"
    mail = Mail.deliver do
        to 'info@yourcompany.com'
        from 'Web Application <info@yourcompany.com>'
        subject '[Action Required] Zoho Import Error'
        text_part do
            body "An error occured while importing contacts to Zoho. Please take a look at the attached CSV file and import manually in Zoho."
        end
        html_part do
            content_type 'text/html; charset=UTF-8'
            body "An error occured while importing contacts to Zoho. Please take a look at the attached CSV file and import manually in Zoho."
        end
        attachments[date_info + "_manual_import.csv"] = {
            :mime_type => 'text/csv',
            :content => File.read(path + "/" + date_info + "_manual_import.csv")
        }
    end
end

puts "Imported #{successfully_saved}/#{accounts.count} accounts to Zoho successfully" if accounts.count > 0

Have fun automating your Zoho import!


Credits Image

Zoho

For the time being, comments are managed by Disqus, a third-party library. I will eventually replace it with another solution, but the timeline is unclear. Considering the amount of data being loaded, if you would like to view comments or post a comment, click on the button below. For more information about why you see this button, take a look at the following article.