Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Custom View Support / Updating multiple records #7

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
229 changes: 229 additions & 0 deletions lib/ruby_zoho.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,233 @@ def self.init_api(api_key, modules, cache_fields)

require 'crm'

class << self
attr_accessor :module_name
end
@module_name = 'Crm'

def initialize(object_attribute_hash = {})
@fields = object_attribute_hash == {} ? RubyZoho.configuration.api.fields(self.class.module_name) :
object_attribute_hash.keys
RubyZoho::Crm.create_accessor(self.class, @fields)
RubyZoho::Crm.create_accessor(self.class, [:module_name])
public_send(:module_name=, self.class.module_name)
update_or_create_attrs(object_attribute_hash)
self
end

def update_or_create_attrs(object_attribute_hash)
retry_counter = object_attribute_hash.count
begin
object_attribute_hash.map { |(k, v)| public_send("#{k}=", v) }
rescue NoMethodError => e
m = e.message.slice(/`(.*?)=/)
RubyZoho::Crm.create_accessor(self.class, [m.gsub(/[`()]*/, '').chop]) unless m.nil?
retry_counter -= 1
retry if retry_counter > 0
end
end

def attr_writers
self.methods.grep(/\w=$/)
end

def self.create_accessor(klass, names)
names.each do |name|
n = name.class == Symbol ? name.to_s : name
n.gsub!(/[()]*/, '')
raise(RuntimeError, "Bad field name: #{name}") unless method_name?(n)
create_getter(klass, n)
create_setter(klass, n)
end
names
end

def self.method_name?(n)
name = n.class == String ? ApiUtils.string_to_symbol(n) : n
return /[@$"]/ !~ name.inspect
end

def self.create_getter(klass, *names)
names.each do |name|
klass.send(:define_method, "#{name}") { instance_variable_get("@#{name}") }
end
end

def self.create_setter(klass, *names)
names.each do |name|
klass.send(:define_method, "#{name}=") { |val| instance_variable_set("@#{name}", val) }
end
end

def self.find(id)
self.find_by_id(id)
end

def self.method_missing(meth, *args, &block)
if meth.to_s =~ /^find_by_(.+)$/
run_find_by_method($1, *args, &block)
else
super
end
end

def method_missing(meth, *args, &block)
if [:seid=, :semodule=].index(meth)
run_create_accessor(self.class, meth)
self.send(meth, args[0])
else
super
end
end

def self.method_is_module?(str_or_sym)
return nil if str_or_sym.nil?
s = str_or_sym.class == String ? str_or_sym : ApiUtils.symbol_to_string(str_or_sym)
possible_module = s[s.length - 1].downcase == 's' ? s : s + 's'
i = RubyZoho.configuration.crm_modules.index(possible_module.capitalize)
return str_or_sym unless i.nil?
nil
end

def run_create_accessor(klass, meth)
method = meth.to_s.chop.to_sym
RubyZoho::Crm.create_accessor(klass, [method])
nil
end

def self.run_find_by_method(attrs, *args, &block)
attrs = attrs.split('_and_')
conditions = Array.new(args.size, '=')
h = RubyZoho.configuration.api.find_records(
self.module_name, ApiUtils.string_to_symbol(attrs[0]), conditions[0], args[0]
)
return h.collect { |r| new(r) } unless h.nil?
nil
end

def self.all #TODO Refactor into low level API
max_records = 200
result = []
i = 1
batch = []
until batch.nil?
batch = RubyZoho.configuration.api.some(self.module_name, i, max_records)
result.concat(batch) unless batch.nil?
break if !batch.nil? && batch.count < max_records
i += max_records
end
result.collect { |r| new(r) }
end

def << object
object.semodule = self.module_name
object.seid = self.id
object.fields << :seid
object.fields << :semodule
save_object(object)
end

def attach_file(file_path, file_name)
RubyZoho.configuration.api.attach_file(self.class.module_name, self.send(primary_key), file_path, file_name)
end

def create(object_attribute_hash)
initialize(object_attribute_hash)
save
end

def self.delete(id)
RubyZoho.configuration.api.delete_record(self.module_name, id)
end

def self.get_from_custom_view(cv_name, to_index=1, from_index=200)
r = RubyZoho.configuration.api.get_records_from_custom_view(self.module_name, cv_name, to_index, from_index)
r ? r.map { |e| new(e) } : []
end

def primary_key
RubyZoho.configuration.api.primary_key(self.class.module_name)
end

def save
h = {}
@fields.each { |f| h.merge!({ f => eval("self.#{f.to_s}") }) }
h.delete_if { |k, v| v.nil? }
r = RubyZoho.configuration.api.add_record(self.class.module_name, h)
up_date(r)
end

def save_object(object)
h = {}
object.fields.each { |f| h.merge!({ f => object.send(f) }) }
h.delete_if { |k, v| v.nil? }
r = RubyZoho.configuration.api.add_record(object.module_name, h)
up_date(r)
end

def self.update(object_attribute_hash)
raise(RuntimeError, 'No ID found', object_attribute_hash.to_s) if object_attribute_hash[:id].nil?
id = object_attribute_hash[:id]
object_attribute_hash.delete(:id)
r = RubyZoho.configuration.api.update_record(self.module_name, id, object_attribute_hash)
new(object_attribute_hash.merge!(r))
end

def up_date(object_attribute_hash)
update_or_create_attrs(object_attribute_hash)
self
end





def self.setup_classes
RubyZoho.configuration.crm_modules.each do |module_name|
klass_name = module_name.chop
c = Class.new(RubyZoho::Crm) do
include RubyZoho
include ActiveModel
extend ActiveModel::Naming

attr_reader :fields
@module_name = module_name
end
const_set(klass_name, c)
end
end

c = Class.new(RubyZoho::Crm) do
def initialize(object_attribute_hash = {})
Crm.module_name = 'Users'
super
end

def self.delete(id)
raise 'Cannot delete users through API'
end

def save
raise 'Cannot delete users through API'
end

def self.all
result = RubyZoho.configuration.api.users('AllUsers')
result.collect { |r| new(r) }
end

def self.find_by_email(email)
r = []
self.all.index { |u| r << u if u.email == email }
r
end

def self.method_missing(meth, *args, &block)
Crm.module_name = 'Users'
super
end
end
Kernel.const_set 'User', c

end
74 changes: 74 additions & 0 deletions lib/zoho_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,58 @@ def first(module_name)
some(module_name, 1, 1)
end

def find_records(module_name, field, condition, value)
sc_field = field == :id ? primary_key(module_name) : ApiUtils.symbol_to_string(field)
return find_record_by_related_id(module_name, sc_field, value) if related_id?(module_name, sc_field)
primary_key?(module_name, sc_field) == false ? find_record_by_field(module_name, sc_field, condition, value) :
find_record_by_id(module_name, value)
end

def find_record_by_field(module_name, sc_field, condition, value)
field = sc_field.rindex('id') ? sc_field.downcase : sc_field
search_condition = '(' + field + '|' + condition + '|' + value + ')'
r = self.class.get(create_url("#{module_name}", 'getSearchRecords'),
:query => {:newFormat => 1, :authtoken => @auth_token, :scope => 'crmapi',
:selectColumns => 'All', :searchCondition => search_condition,
:fromIndex => 1, :toIndex => NUMBER_OF_RECORDS_TO_GET})
check_for_errors(r)
x = REXML::Document.new(r.body).elements.to_a("/response/result/#{module_name}/row")
to_hash(x, module_name)
end

def find_record_by_id(module_name, id)
r = self.class.get(create_url("#{module_name}", 'getRecordById'),
:query => { :newFormat => 1, :authtoken => @auth_token, :scope => 'crmapi',
:selectColumns => 'All', :id => id})
raise(RuntimeError, 'Bad query', "#{module_name} #{id}") unless r.body.index('<error>').nil?
check_for_errors(r)
x = REXML::Document.new(r.body).elements.to_a("/response/result/#{module_name}/row")
to_hash(x, module_name)
end

def find_record_by_related_id(module_name, sc_field, value)
raise(RuntimeError, "[RubyZoho] Not a valid query field #{sc_field} for module #{module_name}") unless
valid_related?(module_name, sc_field)
field = sc_field.downcase
r = self.class.get(create_url("#{module_name}", 'getSearchRecordsByPDC'),
:query => { :newFormat => 1, :authtoken => @auth_token, :scope => 'crmapi',
:selectColumns => 'All', :version => 2, :searchColumn => field,
:searchValue => value})
check_for_errors(r)
x = REXML::Document.new(r.body).elements.to_a("/response/result/#{module_name}/row")
to_hash(x, module_name)
end

def get_records_from_custom_view(module_name, custom_view_name, from_index, to_index)
r = self.class.get(create_url("#{module_name}", 'getCVRecords'),
:query => { :newFormat => 1, :authtoken => @auth_token, :scope => 'crmapi',
:cvName => custom_view_name, :fromIndex => from_index, :toIndex => to_index})
raise(RuntimeError, 'Bad query', "#{module_name} #{id}") unless r.body.index('<error>').nil?
check_for_errors(r)
x = REXML::Document.new(r.body).elements.to_a("/response/result/#{module_name}/row")
to_hash(x, module_name)
end

def method_name?(n)
return /[@$"]/ !~ n.inspect
end
Expand Down Expand Up @@ -151,6 +203,28 @@ def update_record(module_name, id, fields_values_hash)
to_hash_with_id(x_r, module_name)[0]
end

def update_records(module_name, objects)
x = REXML::Document.new
data = x.add_element module_name
count = 0
objects.each do |fields_values_hash|
count = count + 1
row = data.add_element('row', {'no' => count})
fields_values_hash.each_pair { |k, v| add_field(row, ApiUtils.symbol_to_string(k), v) }
end
r = self.class.post(create_url(module_name, 'updateRecords'),
:query => { :authtoken => @auth_token,
:scope => 'crmapi', :version => 4,
:xmlData => x })
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

def user_fields
@@module_fields[:users] = users[0].keys
end

def users(user_type = 'AllUsers')
return @@users unless @@users == [] || user_type == 'Refresh'
r = self.class.get(create_url('Users', 'getUsers'),
Expand Down
Binary file removed rubyzoho-0.1.7.gem
Binary file not shown.
1 change: 0 additions & 1 deletion rubyzoho.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ Gem::Specification.new do |s|
"lib/api_utils.rb",
"lib/ruby_zoho.rb",
"lib/zoho_api.rb",
"rubyzoho-0.1.6.gem",
"rubyzoho.gemspec",
"spec/api_utils_spec.rb",
"spec/fixtures/sample.pdf",
Expand Down