capsule_crm 1.7.0 → 1.8.0
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/CHANGELOG.md +4 -0
- data/lib/capsule_crm/associations/belongs_to_finder.rb +11 -3
- data/lib/capsule_crm/associations/has_many.rb +2 -5
- data/lib/capsule_crm/associations/has_many_association.rb +1 -1
- data/lib/capsule_crm/associations/has_many_proxy.rb +3 -2
- data/lib/capsule_crm/custom_field.rb +15 -4
- data/lib/capsule_crm/organization.rb +12 -0
- data/lib/capsule_crm/person.rb +12 -0
- data/lib/capsule_crm/querying/find_one.rb +8 -0
- data/lib/capsule_crm/version.rb +1 -1
- data/spec/lib/capsule_crm/associations/belongs_to_finder_spec.rb +2 -1
- data/spec/lib/capsule_crm/custom_field_spec.rb +38 -1
- data/spec/lib/capsule_crm/organization_spec.rb +8 -0
- data/spec/lib/capsule_crm/person_spec.rb +8 -0
- data/spec/support/put_customfields.json +20 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40b178add184629b0011c050d6c021eecb3061ed
|
4
|
+
data.tar.gz: 07a406a438880798916012ef6af98fe59786db58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5e6e13677f95912036882050ad7e5babb5a662b813007ffe94ed293a10d5b0b54858aaa9459206d9065cce3fd2583263876bc48f30b26e221b1f149f7013bd8
|
7
|
+
data.tar.gz: 4966758a6dfc65e830d68e133341dd104861e7afce472ea43907ed27fd7c65c3c23e15ed73138cdbd9a8154ee6201966e51f4b1247a13da56fa02ef316f0a3ea
|
data/CHANGELOG.md
CHANGED
@@ -9,7 +9,7 @@ module CapsuleCRM
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def call(id)
|
12
|
-
id ?
|
12
|
+
id ? find_by_parent_id(id) : []
|
13
13
|
end
|
14
14
|
|
15
15
|
private
|
@@ -18,6 +18,10 @@ module CapsuleCRM
|
|
18
18
|
@inverse ||= association.inverse
|
19
19
|
end
|
20
20
|
|
21
|
+
def embedded?
|
22
|
+
inverse.embedded
|
23
|
+
end
|
24
|
+
|
21
25
|
def singular
|
22
26
|
@singular ||= inverse.defined_on.queryable_options.singular
|
23
27
|
end
|
@@ -26,8 +30,12 @@ module CapsuleCRM
|
|
26
30
|
@plural ||= association.defined_on.queryable_options.plural
|
27
31
|
end
|
28
32
|
|
29
|
-
def
|
30
|
-
normalizer.normalize_collection
|
33
|
+
def find_by_parent_id(id)
|
34
|
+
normalizer.normalize_collection(get(path(id))).tap do |collection|
|
35
|
+
collection.each do |item|
|
36
|
+
item.send("#{association.foreign_key}=", id)
|
37
|
+
end if embedded?
|
38
|
+
end
|
31
39
|
end
|
32
40
|
|
33
41
|
def get(path_string)
|
@@ -41,10 +41,8 @@ module CapsuleCRM
|
|
41
41
|
|
42
42
|
if options[:embedded]
|
43
43
|
define_method "save_#{association_name}" do
|
44
|
-
unless
|
45
|
-
|
46
|
-
a = self.send(association_name)
|
47
|
-
a.save
|
44
|
+
unless send(association_name).empty?
|
45
|
+
send(association_name).save
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
@@ -52,7 +50,6 @@ module CapsuleCRM
|
|
52
50
|
after_save :"save_#{association_name}" if respond_to?(:after_save)
|
53
51
|
private :"save_#{association_name}"
|
54
52
|
end
|
55
|
-
|
56
53
|
end
|
57
54
|
|
58
55
|
define_method association_name do
|
@@ -5,7 +5,7 @@ module CapsuleCRM
|
|
5
5
|
|
6
6
|
# Public: Initialize a new CapsuleCRM::Associations::HasManyAssociation
|
7
7
|
#
|
8
|
-
# association_name - The
|
8
|
+
# association_name - The Symbol association name
|
9
9
|
# defined_on - The String name of the class that this association
|
10
10
|
# is defined on
|
11
11
|
# options - The Hash of association options
|
@@ -8,6 +8,7 @@ module CapsuleCRM
|
|
8
8
|
@target_klass = target_klass
|
9
9
|
@source = source
|
10
10
|
@embedded = embedded
|
11
|
+
self
|
11
12
|
end
|
12
13
|
|
13
14
|
def method_missing(name, *args, &block)
|
@@ -25,14 +26,14 @@ module CapsuleCRM
|
|
25
26
|
record = build(attributes).tap do |r|
|
26
27
|
record_not_saved(r) unless parent.persisted?
|
27
28
|
end
|
28
|
-
embedded? ? save : record.save
|
29
|
+
record if embedded? ? save : record.save
|
29
30
|
end
|
30
31
|
|
31
32
|
def create!(attributes = {})
|
32
33
|
record = build(attributes).tap do |r|
|
33
34
|
record_not_saved(r) unless parent.persisted?
|
34
35
|
end
|
35
|
-
embedded? ? save! : record.save!
|
36
|
+
record if embedded? ? save! : record.save!
|
36
37
|
end
|
37
38
|
|
38
39
|
def tap
|
@@ -12,7 +12,7 @@ module CapsuleCRM
|
|
12
12
|
include CapsuleCRM::Serializable
|
13
13
|
|
14
14
|
serializable_config do |config|
|
15
|
-
config.root
|
15
|
+
config.root = 'customField'
|
16
16
|
config.collection_root = 'customFields'
|
17
17
|
end
|
18
18
|
|
@@ -30,13 +30,24 @@ module CapsuleCRM
|
|
30
30
|
validates :id, numericality: { allow_blank: true }
|
31
31
|
validates :label, presence: true
|
32
32
|
|
33
|
-
belongs_to :party
|
34
|
-
belongs_to :opportunity
|
35
|
-
belongs_to :case
|
33
|
+
belongs_to :party, serialize: false
|
34
|
+
belongs_to :opportunity, serialize: false
|
35
|
+
belongs_to :case, serialize: false
|
36
36
|
|
37
37
|
class << self
|
38
38
|
alias :_for_organization :_for_party
|
39
39
|
alias :_for_person :_for_party
|
40
40
|
end
|
41
|
+
|
42
|
+
def parent
|
43
|
+
party || opportunity || self.case
|
44
|
+
end
|
45
|
+
|
46
|
+
def destroy
|
47
|
+
self.date, self.tag, self.boolean, self.text = nil, nil, nil, nil
|
48
|
+
parent.custom_fields.save
|
49
|
+
parent.custom_fields.delete_if { |cf| cf.id == id }
|
50
|
+
true
|
51
|
+
end
|
41
52
|
end
|
42
53
|
end
|
@@ -63,5 +63,17 @@ module CapsuleCRM
|
|
63
63
|
CapsuleCRM::Party.all(options).
|
64
64
|
delete_if { |item| !item.is_a?(CapsuleCRM::Organization) }
|
65
65
|
end
|
66
|
+
|
67
|
+
def self.first
|
68
|
+
raise NotImplementedError.new(
|
69
|
+
[
|
70
|
+
'Unfortunately the capsulecrm.com API returns people and',
|
71
|
+
'organizations in one response. There is no way to query directly',
|
72
|
+
'for people. This means that quite often the first item returned',
|
73
|
+
'will actually be a person and so CapsuleCRM::Organization.first is',
|
74
|
+
'not possible.'
|
75
|
+
].join(' ')
|
76
|
+
)
|
77
|
+
end
|
66
78
|
end
|
67
79
|
end
|
data/lib/capsule_crm/person.rb
CHANGED
@@ -66,6 +66,18 @@ module CapsuleCRM
|
|
66
66
|
delete_if { |item| !item.is_a?(CapsuleCRM::Person) }
|
67
67
|
end
|
68
68
|
|
69
|
+
def self.first
|
70
|
+
raise NotImplementedError.new(
|
71
|
+
[
|
72
|
+
'Unfortunately the capsulecrm.com API returns people and',
|
73
|
+
'organizations in one response. There is no way to query directly',
|
74
|
+
'for people. This means that quite often the first item returned',
|
75
|
+
'will actually be an organization and so CapsuleCRM::Person.first is',
|
76
|
+
'not possible.'
|
77
|
+
].join(' ')
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
69
81
|
private
|
70
82
|
|
71
83
|
# Private: Determines whether the person first name is required. Either the
|
@@ -9,6 +9,14 @@ module CapsuleCRM
|
|
9
9
|
get("/api/#{queryable_options.singular}/#{id}")
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
def reload
|
14
|
+
self.attributes = self.class.find(id).attributes
|
15
|
+
associations.keys.each do |association_name|
|
16
|
+
instance_variable_set(:"@#{association_name}", nil)
|
17
|
+
end
|
18
|
+
self
|
19
|
+
end
|
12
20
|
end
|
13
21
|
end
|
14
22
|
end
|
data/lib/capsule_crm/version.rb
CHANGED
@@ -10,12 +10,13 @@ describe CapsuleCRM::Associations::BelongsToFinder do
|
|
10
10
|
)
|
11
11
|
end
|
12
12
|
let(:inverse) do
|
13
|
-
double('CapsuleCRM::Associations::HasManyAssociation')
|
13
|
+
double('CapsuleCRM::Associations::HasManyAssociation', embedded: false)
|
14
14
|
end
|
15
15
|
let(:normalizer) do
|
16
16
|
double('CapsuleCRM::Normalizer', normalize_collection: [])
|
17
17
|
end
|
18
18
|
let(:finder) { described_class.new(association) }
|
19
|
+
|
19
20
|
before do
|
20
21
|
finder.singular = 'person'
|
21
22
|
finder.plural = 'customfields'
|
@@ -27,7 +27,8 @@ describe CapsuleCRM::CustomField do
|
|
27
27
|
|
28
28
|
it { should be_an(Array) }
|
29
29
|
it do
|
30
|
-
subject.all? { |item| item.is_a?(CapsuleCRM::CustomField) }.
|
30
|
+
subject.all? { |item| item.is_a?(CapsuleCRM::CustomField) }.
|
31
|
+
should be_true
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
@@ -53,4 +54,40 @@ describe CapsuleCRM::CustomField do
|
|
53
54
|
expect(subject.keys.first).to eql('customField')
|
54
55
|
end
|
55
56
|
end
|
57
|
+
|
58
|
+
describe '#destroy' do
|
59
|
+
let(:custom_field) { Fabricate.build(:custom_field, party: person) }
|
60
|
+
let(:person) { Fabricate.build(:person, id: Random.rand(1..10)) }
|
61
|
+
|
62
|
+
def stub_requests
|
63
|
+
stub_request(
|
64
|
+
:get,
|
65
|
+
[
|
66
|
+
'https://1234:@company.capsulecrm.com/api/party/',
|
67
|
+
person.id,
|
68
|
+
'/customfields'
|
69
|
+
].join
|
70
|
+
).to_return(body: File.read('spec/support/no_customfields.json'))
|
71
|
+
# note, this test still passes although completely different data is being
|
72
|
+
# returned from this stub. The data returned should overwrite the
|
73
|
+
# association data
|
74
|
+
stub_request(
|
75
|
+
:put, [
|
76
|
+
'https://1234:@company.capsulecrm.com/api/party/',
|
77
|
+
person.id,
|
78
|
+
'/customfields'
|
79
|
+
].join
|
80
|
+
).to_return(body: File.read('spec/support/put_customfields.json'))
|
81
|
+
end
|
82
|
+
|
83
|
+
before do
|
84
|
+
stub_requests
|
85
|
+
person.custom_fields << custom_field
|
86
|
+
custom_field.destroy
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should remove the custom field from the parent association' do
|
90
|
+
expect(person.custom_fields).not_to include(custom_field)
|
91
|
+
end
|
92
|
+
end
|
56
93
|
end
|
@@ -48,6 +48,14 @@ describe CapsuleCRM::Organization do
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
describe '.first' do
|
52
|
+
subject { described_class }
|
53
|
+
|
54
|
+
it 'should raise a NotImplementedError' do
|
55
|
+
expect { subject.first }.to raise_error(NotImplementedError)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
51
59
|
describe '#custom_fields' do
|
52
60
|
before do
|
53
61
|
stub_request(:get, /\/api\/party\/#{organization.id}\/customfields/).
|
@@ -68,6 +68,14 @@ describe CapsuleCRM::Person do
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
describe '.first' do
|
72
|
+
subject { described_class }
|
73
|
+
|
74
|
+
it 'should raise a NotImplementedError' do
|
75
|
+
expect { subject.first }.to raise_error(NotImplementedError)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
71
79
|
describe '#tasks' do
|
72
80
|
let(:person) { Fabricate.build(:person, id: 1) }
|
73
81
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
{
|
2
|
+
"customFields": {
|
3
|
+
"customField": [
|
4
|
+
{
|
5
|
+
"tag": "Staff",
|
6
|
+
"label": "NI Number",
|
7
|
+
"text": "12345678"
|
8
|
+
},
|
9
|
+
{
|
10
|
+
"tag": "Staff",
|
11
|
+
"label": "Start Date",
|
12
|
+
"date": "2011-03-13T00:00:00Z"
|
13
|
+
},
|
14
|
+
{
|
15
|
+
"label": "Send newsletter",
|
16
|
+
"boolean": "true"
|
17
|
+
}
|
18
|
+
]
|
19
|
+
}
|
20
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capsule_crm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Beedle
|
@@ -388,6 +388,7 @@ files:
|
|
388
388
|
- spec/support/opportunity.json
|
389
389
|
- spec/support/organisation.json
|
390
390
|
- spec/support/person.json
|
391
|
+
- spec/support/put_customfields.json
|
391
392
|
- spec/support/shared_examples/capsule_json.rb
|
392
393
|
- spec/support/shared_examples/contactable.rb
|
393
394
|
- spec/support/shared_examples/deletable.rb
|
@@ -499,6 +500,7 @@ test_files:
|
|
499
500
|
- spec/support/opportunity.json
|
500
501
|
- spec/support/organisation.json
|
501
502
|
- spec/support/person.json
|
503
|
+
- spec/support/put_customfields.json
|
502
504
|
- spec/support/shared_examples/capsule_json.rb
|
503
505
|
- spec/support/shared_examples/contactable.rb
|
504
506
|
- spec/support/shared_examples/deletable.rb
|