capsulecrmii 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +10 -0
- data/README.rdoc +33 -0
- data/Rakefile +9 -0
- data/capsulecrm.gemspec +23 -0
- data/examples.rb +82 -0
- data/lib/capsulecrm.rb +45 -0
- data/lib/capsulecrm/address.rb +23 -0
- data/lib/capsulecrm/base.rb +176 -0
- data/lib/capsulecrm/child.rb +24 -0
- data/lib/capsulecrm/child_collection.rb +14 -0
- data/lib/capsulecrm/collection.rb +14 -0
- data/lib/capsulecrm/contact.rb +27 -0
- data/lib/capsulecrm/custom_field.rb +41 -0
- data/lib/capsulecrm/email.rb +64 -0
- data/lib/capsulecrm/history.rb +32 -0
- data/lib/capsulecrm/history_item.rb +20 -0
- data/lib/capsulecrm/organisation.rb +41 -0
- data/lib/capsulecrm/party.rb +114 -0
- data/lib/capsulecrm/person.rb +126 -0
- data/lib/capsulecrm/phone.rb +15 -0
- data/lib/capsulecrm/record_not_found.rb +1 -0
- data/lib/capsulecrm/recorn_not_recognised.rb +1 -0
- data/lib/capsulecrm/tag.rb +12 -0
- data/lib/capsulecrm/version.rb +3 -0
- data/lib/capsulecrm/website.rb +19 -0
- data/test/create_person_test.rb +36 -0
- data/test/fixtures/responses/create_person.yml +59 -0
- data/test/fixtures/responses/party_history.yml +45 -0
- data/test/fixtures/responses/party_tags.yml +26 -0
- data/test/fixtures/responses/person_find_all.yml +28 -0
- data/test/fixtures/responses/person_find_all_with_limit.yml +26 -0
- data/test/fixtures/responses/person_find_all_with_offset.yml +28 -0
- data/test/fixtures/responses/person_find_by_id.yml +102 -0
- data/test/fixtures/responses/update_person.yml +85 -0
- data/test/fixtures/responses/update_person_without_changes.yml +28 -0
- data/test/party_dot_find_test.rb +40 -0
- data/test/party_dot_history_test.rb +29 -0
- data/test/party_dot_tags_test.rb +30 -0
- data/test/person_dot_find_all_test.rb +48 -0
- data/test/person_dot_find_by_id_test.rb +61 -0
- data/test/test_helper.rb +52 -0
- data/test/update_person_test.rb +46 -0
- metadata +131 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
class CapsuleCRM::Collection < Array
|
2
|
+
|
3
|
+
|
4
|
+
# nodoc
|
5
|
+
def initialize(klass, data)
|
6
|
+
return if data.nil?
|
7
|
+
[data].flatten.each do |attributes|
|
8
|
+
attributes = klass.attributes_from_xml_hash(attributes)
|
9
|
+
self.push klass.new(attributes)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class CapsuleCRM::Contact < CapsuleCRM::Child
|
2
|
+
|
3
|
+
attr_accessor :type
|
4
|
+
define_attribute_methods [:type]
|
5
|
+
|
6
|
+
# nodoc
|
7
|
+
def attributes
|
8
|
+
attrs = {}
|
9
|
+
arr = [:type]
|
10
|
+
arr.each do |key|
|
11
|
+
attrs[key] = self.send(key)
|
12
|
+
end
|
13
|
+
attrs
|
14
|
+
end
|
15
|
+
|
16
|
+
# nodoc
|
17
|
+
def type=(value)
|
18
|
+
type_will_change! unless value == type
|
19
|
+
@type = value
|
20
|
+
end
|
21
|
+
|
22
|
+
# nodoc
|
23
|
+
def self.xml_map
|
24
|
+
map = {'type' => 'type'}
|
25
|
+
super.merge map
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class CapsuleCRM::CustomField < CapsuleCRM::Child
|
2
|
+
|
3
|
+
attr_accessor :boolean
|
4
|
+
attr_accessor :date
|
5
|
+
attr_accessor :label
|
6
|
+
attr_accessor :text
|
7
|
+
|
8
|
+
|
9
|
+
# nodoc
|
10
|
+
def boolean=(value)
|
11
|
+
return @boolean = true if value.to_s == 'true'
|
12
|
+
@boolean = false
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# nodoc
|
17
|
+
def date=(value)
|
18
|
+
value = Time.parse(value) if value.is_a?(String)
|
19
|
+
@date = value
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# nodoc
|
24
|
+
def value
|
25
|
+
date || text || boolean
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# nodoc
|
30
|
+
def self.xml_map
|
31
|
+
map = {
|
32
|
+
'label' => 'label',
|
33
|
+
'text' => 'text',
|
34
|
+
'date' => 'date',
|
35
|
+
'boolean' => 'boolean'
|
36
|
+
}
|
37
|
+
super.merge map
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class CapsuleCRM::Email < CapsuleCRM::Contact
|
2
|
+
|
3
|
+
attr_accessor :address
|
4
|
+
define_attribute_methods [:address]
|
5
|
+
|
6
|
+
|
7
|
+
# nodoc
|
8
|
+
def attributes
|
9
|
+
attrs = {}
|
10
|
+
arr = [:address, :type]
|
11
|
+
arr.each do |key|
|
12
|
+
attrs[key] = self.send(key)
|
13
|
+
end
|
14
|
+
attrs
|
15
|
+
end
|
16
|
+
|
17
|
+
# nodoc
|
18
|
+
def address=(value)
|
19
|
+
address_will_change! unless value == address
|
20
|
+
@address = value
|
21
|
+
end
|
22
|
+
|
23
|
+
# nodoc
|
24
|
+
def dirty_attributes
|
25
|
+
Hash[attributes.select { |k,v| changed.include? k.to_s }]
|
26
|
+
end
|
27
|
+
|
28
|
+
def parent_type
|
29
|
+
return "person" if self.parent.class == CapsuleCRM::Person
|
30
|
+
return "organisation" if self.parent.class == CapsuleCRM::Organisation
|
31
|
+
raise "Unknown Parent Type"
|
32
|
+
end
|
33
|
+
|
34
|
+
# nodoc
|
35
|
+
def save
|
36
|
+
path = ["", "api", parent_type, self.parent.id].join("/")
|
37
|
+
options = {:root => 'person', :path => path}
|
38
|
+
attrs = new_record?? attributes : {:id => id}.merge(dirty_attributes)
|
39
|
+
success = self.class.update id, attrs, options
|
40
|
+
changed_attributes.clear if success
|
41
|
+
success
|
42
|
+
end
|
43
|
+
|
44
|
+
# uses xml_map() to convert :attributes into an xml string
|
45
|
+
def self.attributes_to_xml(attributes, root=nil)
|
46
|
+
xml = {"contacts" => {"email" => {}}}
|
47
|
+
map = xml_map.invert
|
48
|
+
attributes.each do |k,v|
|
49
|
+
key = map[k.to_s]
|
50
|
+
xml["contacts"]["email"][key] = v
|
51
|
+
end
|
52
|
+
xml.to_xml :root => root
|
53
|
+
end
|
54
|
+
|
55
|
+
# nodoc
|
56
|
+
def self.xml_map
|
57
|
+
map = {
|
58
|
+
'emailAddress' => 'address'
|
59
|
+
}
|
60
|
+
super.merge map
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module CapsuleCRM::History
|
2
|
+
# Reload history
|
3
|
+
def history!
|
4
|
+
@history = nil
|
5
|
+
history
|
6
|
+
end
|
7
|
+
|
8
|
+
# Load history if not loaded
|
9
|
+
def history
|
10
|
+
return @history if @history
|
11
|
+
|
12
|
+
path = self.class.get_path
|
13
|
+
path = [path, id, 'history'].join '/'
|
14
|
+
last_response = self.class.get(path)
|
15
|
+
data = last_response['history'].try(:[], 'historyItem')
|
16
|
+
@history = CapsuleCRM::HistoryItem.init_many(self, data)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def add_history(note)
|
21
|
+
if note
|
22
|
+
path = [self.class.get_path, self.id, 'history'].join '/'
|
23
|
+
self.class.create(Hash[{:note => note}], {:root => 'historyItem', :path => path})
|
24
|
+
|
25
|
+
# TODO : Should be optimized so it doesn't reload history each time
|
26
|
+
@history = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
alias :add_note :add_history
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CapsuleCRM::HistoryItem < CapsuleCRM::Child
|
2
|
+
attr_reader :id
|
3
|
+
attr_accessor :type
|
4
|
+
attr_accessor :entry_date
|
5
|
+
attr_accessor :creator
|
6
|
+
attr_accessor :subject
|
7
|
+
attr_accessor :note
|
8
|
+
|
9
|
+
def self.xml_map
|
10
|
+
map = {
|
11
|
+
"id" => 'id',
|
12
|
+
"type" => 'type',
|
13
|
+
"entryDate" => 'entry_date',
|
14
|
+
"creator" => 'creator',
|
15
|
+
"subject" => 'subject',
|
16
|
+
"note" => 'note'
|
17
|
+
}
|
18
|
+
super.merge map
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class CapsuleCRM::Organisation < CapsuleCRM::Party
|
2
|
+
|
3
|
+
attr_accessor :about
|
4
|
+
attr_accessor :name
|
5
|
+
|
6
|
+
|
7
|
+
# nodoc
|
8
|
+
def people
|
9
|
+
return @people if @people
|
10
|
+
path = self.class.get_path
|
11
|
+
path = [path, '/', id, '/people'].join
|
12
|
+
last_response = self.class.get(path)
|
13
|
+
@people = CapsuleCRM::Person.init_many(last_response)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# nodoc
|
18
|
+
def self.init_many(response)
|
19
|
+
data = response['parties']['organisation']
|
20
|
+
CapsuleCRM::Collection.new(self, data)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# nodoc
|
25
|
+
def self.init_one(response)
|
26
|
+
data = response['organisation']
|
27
|
+
new(attributes_from_xml_hash(data))
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# nodoc
|
32
|
+
def self.xml_map
|
33
|
+
map = {
|
34
|
+
'about' => 'about',
|
35
|
+
'name' => 'name'
|
36
|
+
}
|
37
|
+
super.merge map
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class CapsuleCRM::Party < CapsuleCRM::Base
|
2
|
+
include CapsuleCRM::History
|
3
|
+
|
4
|
+
# nodoc
|
5
|
+
def addresses
|
6
|
+
return @addresses if @addresses
|
7
|
+
data = raw_data['contacts'].try(:[], 'address')
|
8
|
+
@addresses = CapsuleCRM::Address.init_many(self, data)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
# nodoc
|
13
|
+
def custom_fields
|
14
|
+
return @custom_fields if @custom_fields
|
15
|
+
path = self.class.get_path
|
16
|
+
path = [path, '/', id, '/customfield'].join
|
17
|
+
last_response = self.class.get(path)
|
18
|
+
data = last_response['customFields'].try(:[], 'customField')
|
19
|
+
@custom_fields = CapsuleCRM::CustomField.init_many(self, data)
|
20
|
+
end
|
21
|
+
|
22
|
+
def tags
|
23
|
+
return @tags if @tags
|
24
|
+
path = self.class.get_path
|
25
|
+
path = [path, '/', id, '/tag'].join
|
26
|
+
last_response = self.class.get(path)
|
27
|
+
data = last_response['tags'].try(:[], 'tag')
|
28
|
+
@tags = CapsuleCRM::Tag.init_many(self, data)
|
29
|
+
end
|
30
|
+
|
31
|
+
def tag_names
|
32
|
+
tags.map(&:name)
|
33
|
+
end
|
34
|
+
|
35
|
+
# nodoc
|
36
|
+
def emails
|
37
|
+
return @emails if @emails
|
38
|
+
data = raw_data['contacts'].try(:[], 'email')
|
39
|
+
@emails = CapsuleCRM::Email.init_many(self, data)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
# nodoc
|
44
|
+
def phone_numbers
|
45
|
+
return @phone_numbers if @phone_numbers
|
46
|
+
data = raw_data['contacts'].try(:[], 'phone')
|
47
|
+
@phone_numbers = CapsuleCRM::Phone.init_many(self, data)
|
48
|
+
end
|
49
|
+
|
50
|
+
# nodoc
|
51
|
+
def websites
|
52
|
+
return @websites if @websites
|
53
|
+
data = raw_data['contacts'].try(:[], 'website')
|
54
|
+
@websites = CapsuleCRM::Website.init_many(self, data)
|
55
|
+
end
|
56
|
+
|
57
|
+
def is?(kind)
|
58
|
+
required_class = kind.to_s.camelize
|
59
|
+
self.class.to_s.include? required_class
|
60
|
+
end
|
61
|
+
|
62
|
+
def tag(value)
|
63
|
+
# unset tags so that if anyone were to request tags again, it
|
64
|
+
# requests an update from the server.
|
65
|
+
@tags = nil
|
66
|
+
path = self.class.get_path
|
67
|
+
tag = URI.escape(value.to_s)
|
68
|
+
path = [path, id, 'tag', tag].join('/')
|
69
|
+
req = self.class.post(path)
|
70
|
+
req.response.code == ("201" || "200")
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def untag(value)
|
75
|
+
# unset tags so that if anyone were to request tags again, it
|
76
|
+
# requests an update from the server.
|
77
|
+
@tags = nil
|
78
|
+
path = self.class.get_path
|
79
|
+
tag = URI.escape(value.to_s)
|
80
|
+
path = [path, id, 'tag', tag].join('/')
|
81
|
+
req = self.class.delete(path)
|
82
|
+
req.response.code == "200"
|
83
|
+
end
|
84
|
+
|
85
|
+
# nodoc
|
86
|
+
def self.get_path
|
87
|
+
'/api/party'
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def self.find_all_by_email(email, options={})
|
92
|
+
options[:email] = email
|
93
|
+
find_all(options)
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# nodoc
|
98
|
+
def self.find_by_email(email)
|
99
|
+
find_all_by_email(email, :limit => 1, :offset => 0).first
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# nodoc
|
104
|
+
def self.search(query, options={})
|
105
|
+
options[:q] = query
|
106
|
+
find_all(options)
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.init_one(response)
|
110
|
+
return CapsuleCRM::Person.init_one(response) if response['person']
|
111
|
+
return CapsuleCRM::Organisation.init_one(response) if response['organisation']
|
112
|
+
raise CapsuleCRM::RecordNotRecognised, "Could not recognise returned entity type: #{response}"
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
class CapsuleCRM::Person < CapsuleCRM::Party
|
2
|
+
|
3
|
+
attr_accessor :about
|
4
|
+
attr_accessor :first_name
|
5
|
+
attr_accessor :job_title
|
6
|
+
attr_accessor :last_name
|
7
|
+
attr_accessor :organisation_id
|
8
|
+
attr_accessor :title
|
9
|
+
attr_accessor :note
|
10
|
+
|
11
|
+
define_attribute_methods [:about, :first_name, :last_name, :job_title, :organisation_id, :title]
|
12
|
+
|
13
|
+
|
14
|
+
# nodoc
|
15
|
+
def attributes
|
16
|
+
attrs = {}
|
17
|
+
arr = [:about, :first_name, :last_name, :title, :job_title]
|
18
|
+
arr.each do |key|
|
19
|
+
attrs[key] = self.send(key)
|
20
|
+
end
|
21
|
+
attrs
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# nodoc
|
26
|
+
def first_name=(value)
|
27
|
+
first_name_will_change! unless value == first_name
|
28
|
+
@first_name = value
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# nodoc
|
33
|
+
def last_name=(value)
|
34
|
+
last_name_will_change! unless value == last_name
|
35
|
+
@last_name = value
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# nodoc
|
40
|
+
def title=(value)
|
41
|
+
title_will_change! unless value == title
|
42
|
+
@title = value
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# nodoc
|
47
|
+
def organisation
|
48
|
+
return nil if organisation_id.nil?
|
49
|
+
@organisation ||= CapsuleCRM::Organisation.find(organisation_id)
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# nodoc
|
54
|
+
def save
|
55
|
+
new_record?? create : update
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
|
62
|
+
# nodoc
|
63
|
+
def create
|
64
|
+
path = '/api/person'
|
65
|
+
options = {:root => 'person', :path => path}
|
66
|
+
new_id = self.class.create dirty_attributes, options
|
67
|
+
unless new_id
|
68
|
+
errors << self.class.last_response.response.message
|
69
|
+
return false
|
70
|
+
end
|
71
|
+
@errors = []
|
72
|
+
changed_attributes.clear
|
73
|
+
self.id = new_id
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# nodoc
|
79
|
+
def dirty_attributes
|
80
|
+
Hash[attributes.select { |k,v| changed.include? k.to_s }]
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
# nodoc
|
85
|
+
def update
|
86
|
+
path = '/api/person/' + id.to_s
|
87
|
+
options = {:root => 'person', :path => path}
|
88
|
+
success = self.class.update id, dirty_attributes, options
|
89
|
+
changed_attributes.clear if success
|
90
|
+
success
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# -- Class methods --
|
95
|
+
|
96
|
+
|
97
|
+
# nodoc
|
98
|
+
def self.init_many(response)
|
99
|
+
data = response['parties']['person']
|
100
|
+
CapsuleCRM::Collection.new(self, data)
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# nodoc
|
105
|
+
def self.init_one(response)
|
106
|
+
data = response['person']
|
107
|
+
new(attributes_from_xml_hash(data))
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# nodoc
|
112
|
+
def self.xml_map
|
113
|
+
map = {
|
114
|
+
'about' => 'about',
|
115
|
+
'firstName' => 'first_name',
|
116
|
+
'jobTitle' => 'job_title',
|
117
|
+
'lastName' => 'last_name',
|
118
|
+
'organisationId' => 'organisation_id',
|
119
|
+
'title' => 'title',
|
120
|
+
'note' => 'note'
|
121
|
+
}
|
122
|
+
super.merge map
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
end
|