capsule_crm 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/capsule_crm.gemspec +1 -0
- data/lib/capsule_crm/associations/belongs_to.rb +64 -0
- data/lib/capsule_crm/associations/has_many.rb +58 -0
- data/lib/capsule_crm/associations/has_many_proxy.rb +47 -0
- data/lib/capsule_crm/associations.rb +3 -0
- data/lib/capsule_crm/opportunity.rb +41 -7
- data/lib/capsule_crm/organization.rb +9 -4
- data/lib/capsule_crm/party.rb +23 -0
- data/lib/capsule_crm/person.rb +238 -267
- data/lib/capsule_crm/version.rb +1 -1
- data/lib/capsule_crm.rb +2 -0
- data/spec/fabricators/opportunity_fabricator.rb +5 -0
- data/spec/fabricators/organization_fabricator.rb +3 -0
- data/spec/lib/capsule_crm/associations/has_many_proxy_spec.rb +71 -0
- data/spec/lib/capsule_crm/associations/has_many_spec.rb +4 -0
- data/spec/lib/capsule_crm/opportunity_spec.rb +113 -9
- data/spec/lib/capsule_crm/organization_spec.rb +24 -0
- data/spec/spec_helper.rb +5 -3
- data/spec/support/all_people.json +16 -0
- data/spec/support/deleted_opportunities.json +14 -0
- data/spec/support/organisation.json +8 -0
- metadata +35 -2
data/lib/capsule_crm/person.rb
CHANGED
@@ -1,294 +1,265 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module CapsuleCRM
|
2
|
+
class Person < CapsuleCRM::Party
|
3
|
+
include Virtus
|
3
4
|
|
4
|
-
|
5
|
+
include CapsuleCRM::Contactable
|
6
|
+
include CapsuleCRM::Associations::BelongsTo
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
include ActiveModel::Validations
|
10
|
-
include ActiveModel::Validations::Callbacks
|
8
|
+
extend ActiveModel::Naming
|
9
|
+
include ActiveModel::Conversion
|
10
|
+
include ActiveModel::Validations
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
attribute :organisation_id
|
12
|
+
attribute :id, Integer
|
13
|
+
attribute :title
|
14
|
+
attribute :first_name
|
15
|
+
attribute :last_name
|
16
|
+
attribute :job_title
|
17
|
+
attribute :about
|
18
|
+
attribute :organisation_name
|
20
19
|
|
21
|
-
|
22
|
-
|
20
|
+
belongs_to :organization, class_name: 'CapsuleCRM::Organization',
|
21
|
+
foreign_key: :organisation_id
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
# attributes - The Hash of attributes (default: {}):
|
27
|
-
# :first_name - The String person first name
|
28
|
-
# :last_name - The String person last name
|
29
|
-
# :job_title - The String job title
|
30
|
-
# :about - The String information about the person
|
31
|
-
# :organisation_name - The String name of the organisation. If
|
32
|
-
# this organisation does not exist in capsule then a new one
|
33
|
-
# will be created on save
|
34
|
-
# :organisation_id - The Integer ID of the organisation in
|
35
|
-
# capsulecrm.
|
36
|
-
#
|
37
|
-
# Examples
|
38
|
-
#
|
39
|
-
# CapsuleCRM::Person.new
|
40
|
-
#
|
41
|
-
# Returns a CapsuleCRM::Person
|
42
|
-
def attributes=(attributes)
|
43
|
-
CapsuleCRM::HashHelper.underscore_keys!(attributes)
|
44
|
-
super(attributes)
|
45
|
-
self
|
46
|
-
end
|
23
|
+
validates :first_name, presence: { if: :first_name_required? }
|
24
|
+
validates :last_name, presence: { if: :last_name_required? }
|
47
25
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
# :email - The String email address to search for
|
56
|
-
# :tag - The String tag to search for
|
57
|
-
# :start - The Integer first record to be returned in pagination.
|
58
|
-
# The results start with an index of 1
|
59
|
-
# :limit - The Integer maximum number of matching records to be
|
60
|
-
# returned
|
61
|
-
#
|
62
|
-
# Examples
|
63
|
-
#
|
64
|
-
# CapsuleCRM::Person.all
|
65
|
-
#
|
66
|
-
# CapsuleCRM::Person.all(q: "a search query", start: 10, limit: 20)
|
67
|
-
#
|
68
|
-
# Returns a ResultsProxy of organisations
|
69
|
-
def self.all(options = {})
|
70
|
-
init_collection(
|
71
|
-
CapsuleCRM::Connection.get('/api/party', options)['parties']['person']
|
72
|
-
)
|
73
|
-
end
|
26
|
+
def self._for_organization(organization_id)
|
27
|
+
init_collection(
|
28
|
+
CapsuleCRM::Connection.get(
|
29
|
+
"/api/party/#{organization_id}/people"
|
30
|
+
)['parties']['person']
|
31
|
+
)
|
32
|
+
end
|
74
33
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
34
|
+
# Public: Set the attributes of a person
|
35
|
+
#
|
36
|
+
# attributes - The Hash of attributes (default: {}):
|
37
|
+
# :first_name - The String person first name
|
38
|
+
# :last_name - The String person last name
|
39
|
+
# :job_title - The String job title
|
40
|
+
# :about - The String information about the person
|
41
|
+
# :organisation_name - The String name of the organisation. If
|
42
|
+
# this organisation does not exist in capsule then a new one
|
43
|
+
# will be created on save
|
44
|
+
# :organisation_id - The Integer ID of the organisation in
|
45
|
+
# capsulecrm.
|
46
|
+
#
|
47
|
+
# Examples
|
48
|
+
#
|
49
|
+
# CapsuleCRM::Person.new
|
50
|
+
#
|
51
|
+
# Returns a CapsuleCRM::Person
|
52
|
+
def attributes=(attributes)
|
53
|
+
CapsuleCRM::HashHelper.underscore_keys!(attributes)
|
54
|
+
super(attributes)
|
55
|
+
self
|
56
|
+
end
|
87
57
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
58
|
+
# Public: Create a new person in capsulecrm
|
59
|
+
#
|
60
|
+
# attributes - The Hash of person attributes (default: {}):
|
61
|
+
# :first_name - The String first name
|
62
|
+
# :last_name - The String last name
|
63
|
+
# :job_title - The String job title
|
64
|
+
# :about - The String information about the person
|
65
|
+
# :organisation_name - The String organisation name. If now
|
66
|
+
# :organisation_id is supplied, then a new one will be created
|
67
|
+
# with this name
|
68
|
+
# :organisation_id - The Integer ID of the organisation this
|
69
|
+
# person belongs to
|
70
|
+
#
|
71
|
+
# Examples
|
72
|
+
#
|
73
|
+
# CapsuleCRM::Person.create(first_name: 'Matt', last_name: 'Beedle')
|
74
|
+
#
|
75
|
+
# Returns a CapsuleCRM::Person
|
76
|
+
def self.create(attributes = {})
|
77
|
+
new(attributes).tap(&:save)
|
78
|
+
end
|
109
79
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
80
|
+
# Public: Create a new person in capsulecrm and raise a
|
81
|
+
# CapsuleCRM::Errors::InvalidRecord error if not possible
|
82
|
+
#
|
83
|
+
# attributes - The Hash of person attributes (default: {}):
|
84
|
+
# :first_name - The String first name
|
85
|
+
# :last_name - The String last name
|
86
|
+
# :job_title - The String job title
|
87
|
+
# :about - The String information about the person
|
88
|
+
# :organisation_name - The String organisation name. If now
|
89
|
+
# :organisation_id is supplied, then a new one will be created
|
90
|
+
# with this name
|
91
|
+
# :organisation_id - The Integer ID of the organisation this
|
92
|
+
# person belongs to
|
93
|
+
#
|
94
|
+
# Examples
|
95
|
+
#
|
96
|
+
# CapsuleCRM::Person.create!(first_name: 'Matt', last_name: 'Beedle')
|
97
|
+
#
|
98
|
+
# Returns a CapsuleCRM
|
99
|
+
def self.create!(attributes = {})
|
100
|
+
new(attributes).tap(&:save!)
|
101
|
+
end
|
132
102
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
103
|
+
# Public: If the person already exists in capsule then update them,
|
104
|
+
# otherwise create a new person
|
105
|
+
#
|
106
|
+
# Examples
|
107
|
+
#
|
108
|
+
# person = CapsuleCRM::Person.new(first_name: 'Matt')
|
109
|
+
# person.save
|
110
|
+
#
|
111
|
+
# person = CapsuleCRM::Person.find(1)
|
112
|
+
# person.first_name = 'Matt'
|
113
|
+
# person.save
|
114
|
+
#
|
115
|
+
# Returns a CapsuleCRM::Person
|
116
|
+
def save
|
117
|
+
if valid?
|
118
|
+
new_record? ? create_record : update_record
|
119
|
+
else
|
120
|
+
false
|
121
|
+
end
|
151
122
|
end
|
152
|
-
end
|
153
123
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
124
|
+
# Public: If the person already exists in capsule then update them,
|
125
|
+
# otherwise create a new person. If the person is not valid then a
|
126
|
+
# CapsuleCRM::Errors::RecordInvalid exception is raised
|
127
|
+
#
|
128
|
+
# Examples
|
129
|
+
#
|
130
|
+
# person = CapsuleCRM::Person.new(first_name: 'Matt')
|
131
|
+
# person.save
|
132
|
+
#
|
133
|
+
# person = CapsuleCRM::Person.find(1)
|
134
|
+
# person.first_name = 'Matt'
|
135
|
+
# person.save
|
136
|
+
#
|
137
|
+
# Returns a CapsuleCRM::Person
|
138
|
+
def save!
|
139
|
+
if valid?
|
140
|
+
new_record? ? create_record : update_record
|
141
|
+
else
|
142
|
+
raise CapsuleCRM::Errors::RecordInvalid.new(self)
|
143
|
+
end
|
173
144
|
end
|
174
|
-
end
|
175
145
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
146
|
+
# Public: Update the person in capsule
|
147
|
+
#
|
148
|
+
# attributes - The Hash of person attributes (default: {}):
|
149
|
+
# :first_name - The String first name
|
150
|
+
# :last_name - The String last name
|
151
|
+
# :job_title - The String job title
|
152
|
+
# :about - The String information about the person
|
153
|
+
# :organisation_name - The String organisation name
|
154
|
+
# :organisation_id - The String organisation id
|
155
|
+
#
|
156
|
+
# Examples
|
157
|
+
#
|
158
|
+
# person = CapsuleCRM::Person.find(1)
|
159
|
+
# person.update_attributes first_name: 'Matt', last_name: 'Beedle'
|
160
|
+
#
|
161
|
+
# Returns a CapsuleCRM::Person
|
162
|
+
def update_attributes(attributes = {})
|
163
|
+
self.attributes = attributes
|
164
|
+
save
|
165
|
+
end
|
196
166
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
167
|
+
# Public: Update the person in capsule. If the person is not valid then a
|
168
|
+
# CapsuleCRM::Errors::RecordInvalid exception will be raised
|
169
|
+
#
|
170
|
+
# attributes - The Hash of person attributes (default: {}):
|
171
|
+
# :first_name - The String first name
|
172
|
+
# :last_name - The String last name
|
173
|
+
# :job_title - The String job title
|
174
|
+
# :about - The String information about the person
|
175
|
+
# :organisation_name - The String organisation name
|
176
|
+
# :organisation_id - The String organisation id
|
177
|
+
#
|
178
|
+
# Examples
|
179
|
+
#
|
180
|
+
# person = CapsuleCRM::Person.find(1)
|
181
|
+
# person.update_attributes first_name: 'Matt', last_name: 'Beedle'
|
182
|
+
#
|
183
|
+
# Returns a CapsuleCRM::Person
|
184
|
+
def update_attributes!(attributes = {})
|
185
|
+
self.attributes = attributes
|
186
|
+
save!
|
187
|
+
end
|
218
188
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
189
|
+
def destroy
|
190
|
+
self.id = nil if CapsuleCRM::Connection.delete("/api/party/#{id}")
|
191
|
+
self
|
192
|
+
end
|
223
193
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
194
|
+
# Public: Determine whether this CapsuleCRM::Person is a new record or not
|
195
|
+
#
|
196
|
+
# Returns a Boolean
|
197
|
+
def new_record?
|
198
|
+
!id
|
199
|
+
end
|
230
200
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
201
|
+
# Public: Determine whether or not this CapsuleCRM::Person has already been
|
202
|
+
# persisted to capsulecrm
|
203
|
+
#
|
204
|
+
# Returns a Boolean
|
205
|
+
def persisted?
|
206
|
+
!new_record?
|
207
|
+
end
|
238
208
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
209
|
+
# Public: Build a hash of attributes and merge in the attributes for the
|
210
|
+
# contact information
|
211
|
+
#
|
212
|
+
# Examples
|
213
|
+
#
|
214
|
+
# person.to_capsule_json
|
215
|
+
#
|
216
|
+
# Returns a Hash
|
217
|
+
def to_capsule_json
|
218
|
+
{
|
219
|
+
person: CapsuleCRM::HashHelper.camelize_keys(
|
220
|
+
attributes.dup.delete_if { |key, value| value.blank? }.
|
221
|
+
merge(contacts: contacts.to_capsule_json)
|
222
|
+
)
|
223
|
+
}.stringify_keys
|
224
|
+
end
|
255
225
|
|
256
|
-
|
226
|
+
private
|
257
227
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
228
|
+
def create_record
|
229
|
+
self.attributes = CapsuleCRM::Connection.post(
|
230
|
+
'/api/person', to_capsule_json
|
231
|
+
)
|
232
|
+
self
|
233
|
+
end
|
264
234
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
235
|
+
def update_record
|
236
|
+
CapsuleCRM::Connection.put("/api/person/#{id}", attributes)
|
237
|
+
self
|
238
|
+
end
|
269
239
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
240
|
+
# Private: Build a ResultsProxy from a Array of CapsuleCRM::Person attributes
|
241
|
+
#
|
242
|
+
# collection - The Array of CapsuleCRM::Person attributes hashes
|
243
|
+
#
|
244
|
+
# Returns a CapsuleCRM::ResultsProxy
|
245
|
+
def self.init_collection(collection)
|
246
|
+
CapsuleCRM::ResultsProxy.new(collection.map { |item| new item })
|
247
|
+
end
|
278
248
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
249
|
+
# Private: Determines whether the person first name is required. Either the
|
250
|
+
# first or the last name is always required
|
251
|
+
#
|
252
|
+
# Returns a Boolean
|
253
|
+
def first_name_required?
|
254
|
+
last_name.blank?
|
255
|
+
end
|
286
256
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
257
|
+
# Private: Determines whether the person last name is required. Either the
|
258
|
+
# first or the last name is always required
|
259
|
+
#
|
260
|
+
# Return a Boolean
|
261
|
+
def last_name_required?
|
262
|
+
first_name.blank?
|
263
|
+
end
|
293
264
|
end
|
294
265
|
end
|
data/lib/capsule_crm/version.rb
CHANGED
data/lib/capsule_crm.rb
CHANGED
@@ -3,9 +3,11 @@ require 'faraday'
|
|
3
3
|
require 'faraday_middleware'
|
4
4
|
require 'virtus'
|
5
5
|
require 'capsule_crm/capsule_jsonable'
|
6
|
+
require 'capsule_crm/associations'
|
6
7
|
require 'capsule_crm/address'
|
7
8
|
require 'capsule_crm/connection'
|
8
9
|
require 'capsule_crm/email'
|
10
|
+
require 'capsule_crm/party'
|
9
11
|
require 'capsule_crm/phone'
|
10
12
|
require 'capsule_crm/website'
|
11
13
|
require 'capsule_crm/hash_helper'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Parent
|
4
|
+
include Virtus
|
5
|
+
include CapsuleCRM::Associations::HasMany
|
6
|
+
|
7
|
+
attribute :id, Integer
|
8
|
+
|
9
|
+
has_many :children, class_name: 'Child', source: :parent
|
10
|
+
end
|
11
|
+
|
12
|
+
class Child
|
13
|
+
include Virtus
|
14
|
+
include CapsuleCRM::Associations::BelongsTo
|
15
|
+
|
16
|
+
attribute :name
|
17
|
+
|
18
|
+
belongs_to :parent
|
19
|
+
|
20
|
+
def self._for_parent(parent_id)
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
|
24
|
+
def save
|
25
|
+
@persisted = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def persisted?
|
29
|
+
@persisted
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe CapsuleCRM::Associations::HasManyProxy do
|
34
|
+
let(:proxy) do
|
35
|
+
CapsuleCRM::Associations::HasManyProxy.new(
|
36
|
+
parent, Child, target, :parent
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:parent) { Parent.new }
|
41
|
+
|
42
|
+
let(:target) { [] }
|
43
|
+
|
44
|
+
describe '#build' do
|
45
|
+
before { parent.children.build(name: 'a test name') }
|
46
|
+
|
47
|
+
it 'should build a child object' do
|
48
|
+
parent.children.first.should be_a(Child)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should set the child object attributes' do
|
52
|
+
parent.children.first.name.should eql('a test name')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should add an object to the target' do
|
56
|
+
parent.children.length.should eql(1)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should add the target to the parent' do
|
60
|
+
parent.children.length.should eql(1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#create' do
|
65
|
+
before { parent.children.create(name: 'a test name') }
|
66
|
+
|
67
|
+
it 'should persist the child' do
|
68
|
+
parent.children.last.should be_persisted
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|