capsulecrm-b 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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/opportunity.rb +60 -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/lib/capsulecrm.rb +46 -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 +158 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
= CapsuleCRM
|
2
|
+
|
3
|
+
This is a ruby wrapper for the CapsuleCRM API. It is alpha software and should be considered a work in progress. It currently supports People & Organisations. There is support for CustomFields & Contacts but they are read-only.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
[sudo] gem install capsulecrm
|
8
|
+
|
9
|
+
gem 'capsulecrm' # rails
|
10
|
+
require 'capsulecrm' # non-rails
|
11
|
+
|
12
|
+
== Getting started
|
13
|
+
|
14
|
+
You will need to supply the gem with your CapsuleCRM API token and account name. The account name is the first part of your CapsuleCRM url:
|
15
|
+
|
16
|
+
CapsuleCRM.account_name = "test-account" # http://test-account.capsulecrm.com
|
17
|
+
CapsuleCRM.api_token = 'MY_API_TOKEN'
|
18
|
+
CapsuleCRM.initialize!
|
19
|
+
|
20
|
+
If you're using rails, you can put that in config/initializers/capsulecrm.rb
|
21
|
+
|
22
|
+
|
23
|
+
== Usage
|
24
|
+
|
25
|
+
Please see examples.rb for usage examples
|
26
|
+
|
27
|
+
== Feedback
|
28
|
+
|
29
|
+
Bug reports, feature requests and patches are welcome. Please create an issue on the github issue tracker.
|
30
|
+
|
31
|
+
== License
|
32
|
+
|
33
|
+
MIT License. Copyright 2011 Ahmed Adam
|
data/Rakefile
ADDED
data/capsulecrm.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "capsulecrm/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "capsulecrm-b"
|
7
|
+
s.version = CapsuleCRM::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ahmed Adam", "dsimard", "FWMatt"]
|
10
|
+
s.email = ["ahmed.msgs@gmail.com", "dsimard@azanka.ca", "matt@futureworkshops.com"]
|
11
|
+
s.homepage = "https://github.com/dsimard/capsulecrm"
|
12
|
+
s.summary = %q{CapsuleCRM API Gem}
|
13
|
+
s.description = %q{CapsuleCRM API Gem}
|
14
|
+
|
15
|
+
s.add_dependency 'httparty', '~> 0.7'
|
16
|
+
s.add_dependency 'activemodel', '~> 3.0'
|
17
|
+
s.add_dependency 'activesupport', '~> 3.0'
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
data/examples.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# NOTE: CapsuleCRM::Person and CapsuleCRM::Organisation have virtually identically methods.
|
2
|
+
require 'capsulecrm'
|
3
|
+
|
4
|
+
# find by id
|
5
|
+
person = CapsuleCRM::Person.find 123
|
6
|
+
|
7
|
+
# or if you don't know what you are searching for Party
|
8
|
+
something = CapsuleCRM::Party.find 123
|
9
|
+
something.is?(:person)
|
10
|
+
something.is?(:organisation)
|
11
|
+
|
12
|
+
# find by email
|
13
|
+
person = CapsuleCRM::Person.find_by_email 'foo@example.com'
|
14
|
+
|
15
|
+
# find all
|
16
|
+
person = CapsuleCRM::Person.find :all, :offset => 10, :limit => 5
|
17
|
+
|
18
|
+
# find by search term (searches name, telephone number and searchable custom fields)
|
19
|
+
person = CapsuleCRM::Person.search 'fred', :offset => 10, :limit => 5
|
20
|
+
|
21
|
+
# CapsuleCRM::Person attributes
|
22
|
+
person.id
|
23
|
+
person.title
|
24
|
+
person.first_name
|
25
|
+
person.last_name
|
26
|
+
person.job_title
|
27
|
+
person.about
|
28
|
+
|
29
|
+
# Add a note to the history
|
30
|
+
person.add_history "This is a note"
|
31
|
+
|
32
|
+
# update a person object
|
33
|
+
person.first_name = "Homer"
|
34
|
+
person.last_name = "Simpson"
|
35
|
+
person.save # returns true/false
|
36
|
+
|
37
|
+
# create a person object
|
38
|
+
person = CapsuleCRM::Person.new
|
39
|
+
person.first_name = "Marge"
|
40
|
+
person.last_name = "Simpson"
|
41
|
+
person.save # returns true/false
|
42
|
+
|
43
|
+
|
44
|
+
# get the person's organisation
|
45
|
+
person.organisation # CapsuleCRM::Organisation
|
46
|
+
|
47
|
+
# CapsuleCRM::Organisation attributes:
|
48
|
+
organisation.about
|
49
|
+
organisation.name
|
50
|
+
|
51
|
+
|
52
|
+
# Contacts: CapsuleCRM::Phone (read-only)
|
53
|
+
person.phone_numbers # CapsuleCRM::Collection
|
54
|
+
person.phone_numbers.first.number # 01234 56789
|
55
|
+
person.phone_numbers.first.type # work
|
56
|
+
|
57
|
+
# Contacts: CapsuleCRM::Website (read-only)
|
58
|
+
party.websites # CapsuleCRM::Collection
|
59
|
+
party.websites.first.url # http://google.com
|
60
|
+
party.websites.first.web_address # http://google.com
|
61
|
+
|
62
|
+
# Contacts: CapsuleCRM::Email (read-only)
|
63
|
+
person.emails # CapsuleCRM::Collection
|
64
|
+
person.emails.first.address # 'foo@example.com'
|
65
|
+
person.emails.first.type # 'home'
|
66
|
+
|
67
|
+
# Contacts: CapsuleCRM::Address (read-only)
|
68
|
+
person.addresses # CapsuleCRM::Collection
|
69
|
+
person.addresses.first.street # 10 Somestreet
|
70
|
+
person.addresses.first.city # Manchester
|
71
|
+
person.addresses.first.state # Greater Manchester
|
72
|
+
person.addresses.first.zip # ME10 7TR
|
73
|
+
person.addresses.first.country # United Kingdom
|
74
|
+
|
75
|
+
# CapsuleCRM::CustomFields (read-only)
|
76
|
+
person.custom_fields # CapsuleCRM::Collection
|
77
|
+
person.custom_fields.first.label # 'Favourite colour'
|
78
|
+
person.custom_fields.first.value # 'Blue'
|
79
|
+
|
80
|
+
# CapsuleCRM::Tag (read-only)
|
81
|
+
person.tags # CapsuleCRM::Collection
|
82
|
+
person.tag_names # ["array", "of all", "tags", "as strings"]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CapsuleCRM::Address < CapsuleCRM::Contact
|
2
|
+
|
3
|
+
attr_accessor :street
|
4
|
+
attr_accessor :city
|
5
|
+
attr_accessor :state
|
6
|
+
attr_accessor :zip
|
7
|
+
attr_accessor :country
|
8
|
+
|
9
|
+
|
10
|
+
# nodoc
|
11
|
+
def self.xml_map
|
12
|
+
map = {
|
13
|
+
'street' => 'street',
|
14
|
+
'city' => 'city',
|
15
|
+
'state' => 'state',
|
16
|
+
'zip' => 'zip',
|
17
|
+
'country' => 'country'
|
18
|
+
}
|
19
|
+
super.merge map
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module CapsuleCRM
|
2
|
+
class Base
|
3
|
+
include HTTParty
|
4
|
+
include ActiveModel::Dirty
|
5
|
+
|
6
|
+
|
7
|
+
# This is needed for PUT and POST requests because the capsule API returns html
|
8
|
+
# if the request is unsuccessful. HTTParty's default xlm parser crashes if fed
|
9
|
+
# html so this parser is used for PUT/POST
|
10
|
+
class Parser::Simple < HTTParty::Parser
|
11
|
+
def parse; body; end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
# -- Attributes --
|
16
|
+
attr_accessor :id
|
17
|
+
attr_accessor :raw_data
|
18
|
+
@@last_response = nil
|
19
|
+
|
20
|
+
|
21
|
+
# -- HttpParty --
|
22
|
+
format :xml
|
23
|
+
headers 'User-Agent' => 'CapsuleCRM ruby gem'
|
24
|
+
|
25
|
+
|
26
|
+
# nodoc
|
27
|
+
def initialize(attributes={})
|
28
|
+
attributes.each do |name, value|
|
29
|
+
send("#{name}=", value)
|
30
|
+
end
|
31
|
+
changed_attributes.clear
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# nodoc
|
36
|
+
def ==(other)
|
37
|
+
return false if other.nil?
|
38
|
+
id == other.id
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# nodoc
|
43
|
+
def id
|
44
|
+
return nil if @id.nil?
|
45
|
+
@id.to_i
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# nodoc
|
50
|
+
def errors
|
51
|
+
@errors ||= []
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# nodoc
|
56
|
+
def new_record?
|
57
|
+
id.nil?
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# -- Class Methods --
|
62
|
+
|
63
|
+
|
64
|
+
# nodoc
|
65
|
+
def self.find(what, options={})
|
66
|
+
return find_all(options) if what == :all
|
67
|
+
find_one(what)
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# for debugging
|
72
|
+
def self.last_response
|
73
|
+
@@last_response
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
|
80
|
+
# uses xml_map() to convert the xml hash from response.data into an attributes hash
|
81
|
+
def self.attributes_from_xml_hash(hash)
|
82
|
+
attributes = {:raw_data => hash}
|
83
|
+
xml_map.each { |k,v| attributes[v] = hash[k] }
|
84
|
+
attributes
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
# uses xml_map() to convert :attributes into an xml string
|
89
|
+
def self.attributes_to_xml(attributes, root=nil)
|
90
|
+
xml = {}
|
91
|
+
map = xml_map.invert
|
92
|
+
attributes.each do |k,v|
|
93
|
+
key = map[k.to_s]
|
94
|
+
xml[key] = v
|
95
|
+
end
|
96
|
+
xml.to_xml :root => root
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# nodoc
|
101
|
+
def self.find_one(id)
|
102
|
+
path = get_path + '/' + id.to_s
|
103
|
+
@@last_response = get(path)
|
104
|
+
raise_404(id) if last_response.code == 404
|
105
|
+
init_one(last_response)
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
# nodoc
|
110
|
+
def self.find_all(options={}, path=nil)
|
111
|
+
path ||= get_path
|
112
|
+
params = query_params(options)
|
113
|
+
@@last_response = get(path, :query => params)
|
114
|
+
init_many(last_response)
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# over-ride in sub-classes
|
119
|
+
def self.get_path
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
# capsule API uses :start. :offset is prob more familiar to ruby/active_record users
|
124
|
+
def self.query_params(options)
|
125
|
+
params = options.dup
|
126
|
+
params[:start] = params.delete(:offset) if params.has_key?(:offset)
|
127
|
+
params
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
# nodoc
|
132
|
+
def self.raise_404(id)
|
133
|
+
err = "Could not find #{name} with id #{id}"
|
134
|
+
raise CapsuleCRM::RecordNotFound, err
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
# creates a new object, and returns the ID
|
139
|
+
# returns false if something went wrong (use last_response() to debug)
|
140
|
+
def self.create(attributes, options={})
|
141
|
+
return false if attributes.empty?
|
142
|
+
xml = attributes_to_xml(attributes, options.delete(:root))
|
143
|
+
@@last_response = post options[:path], xml_request_options(xml)
|
144
|
+
return false unless last_response.code == 201
|
145
|
+
last_response.headers['location'].split('/').last
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# updates an object with the given id, returns true on success, false
|
150
|
+
# on failure.
|
151
|
+
def self.update(id, attributes, options={})
|
152
|
+
return true if attributes.empty?
|
153
|
+
xml = attributes_to_xml(attributes, options.delete(:root))
|
154
|
+
@@last_response = put options[:path], xml_request_options(xml)
|
155
|
+
last_response.code == 200
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
# nodoc
|
160
|
+
def self.xml_map
|
161
|
+
{'id' => 'id'}
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
# needed for PUT and POST operations
|
166
|
+
def self.xml_request_options(xml)
|
167
|
+
options = {
|
168
|
+
:body => xml,
|
169
|
+
:headers => {'Content-Type' => 'text/xml'},
|
170
|
+
:parser => Parser::Simple
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CapsuleCRM::Child < CapsuleCRM::Base
|
2
|
+
attr_accessor :parent
|
3
|
+
|
4
|
+
|
5
|
+
# nodoc
|
6
|
+
def initialize(parent, attributes={})
|
7
|
+
@parent = parent
|
8
|
+
super(attributes)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
# nodoc
|
13
|
+
def self.init_many(parent, data)
|
14
|
+
CapsuleCRM::ChildCollection.new(parent, self, data)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# nodoc
|
19
|
+
def self.init_one(parent, data)
|
20
|
+
new(parent, attributes_from_xml_map(data))
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CapsuleCRM::ChildCollection < CapsuleCRM::Collection
|
2
|
+
|
3
|
+
|
4
|
+
# nodoc
|
5
|
+
def initialize(parent, 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(parent, attributes)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
end
|
@@ -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,60 @@
|
|
1
|
+
class CapsuleCRM::Opportunity < CapsuleCRM::Base
|
2
|
+
|
3
|
+
attr_accessor :name
|
4
|
+
attr_accessor :party_id
|
5
|
+
attr_accessor :currency
|
6
|
+
attr_accessor :value
|
7
|
+
attr_accessor :duration_basis
|
8
|
+
attr_accessor :duration
|
9
|
+
attr_accessor :expected_close_date
|
10
|
+
attr_accessor :actual_close_date
|
11
|
+
attr_accessor :milestone
|
12
|
+
attr_accessor :updated_on
|
13
|
+
attr_accessor :created_on
|
14
|
+
|
15
|
+
# nodoc
|
16
|
+
def self.xml_map
|
17
|
+
map = {
|
18
|
+
'name' => 'name',
|
19
|
+
'partyId' => 'party_id',
|
20
|
+
'currency' => 'currency',
|
21
|
+
'value' => 'value',
|
22
|
+
'durationBasis' => 'duration_basis',
|
23
|
+
'expectedCloseDate' => 'expected_close_date',
|
24
|
+
'actualCloseDate' => 'actual_close_date',
|
25
|
+
'milestone' => 'milestone',
|
26
|
+
'updatedOn' => 'updated_on',
|
27
|
+
'createdOn' => 'created_on',
|
28
|
+
}
|
29
|
+
super.merge map
|
30
|
+
end
|
31
|
+
|
32
|
+
def all
|
33
|
+
return @opportunities if @opportunities
|
34
|
+
path = self.class.get_path
|
35
|
+
last_response = self.class.get(path)
|
36
|
+
@opportunities = CapsuleCRM::Opportunity.init_many(last_response)
|
37
|
+
end
|
38
|
+
|
39
|
+
# nodoc
|
40
|
+
def self.get_path
|
41
|
+
'/api/opportunity'
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# nodoc
|
46
|
+
def self.init_many(response)
|
47
|
+
data = response['opportunities']['opportunity']
|
48
|
+
CapsuleCRM::Collection.new(self, data)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# nodoc
|
53
|
+
def self.init_one(response)
|
54
|
+
data = response['opportunity']
|
55
|
+
new(attributes_from_xml_hash(data))
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
end
|