amorail 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20a8ca62be5f80149cddb2e7e82442d611b9fe32
4
- data.tar.gz: 90ce153c4740de2c2049adcc2f473f6f1b0d9b57
3
+ metadata.gz: 6a49cf3e73052b401ec558f46cf546671cefd4ba
4
+ data.tar.gz: 05204059536051197800da4bd8f784c9dd13b0d2
5
5
  SHA512:
6
- metadata.gz: c0d2b86bbfef3d13494baffbe381ccf0e4ce4162100cecb37c92a301324c4d87fd7295a2873ba58ed04a1f3c8acadc34b2d281b6d887a9cb810328702617e418
7
- data.tar.gz: d8718c7c448a91b45be58d25ae26970c8c4b222c0dbee8682223548eb00df93fdaba99a340c508e961517b34ee1f026916c598dceecb74b933b97ccf051da95c
6
+ metadata.gz: ecdea4ff97ea0018b2b25cce5e049fef9fb8c7ecea9fffe88777f4b25fa0b98378233d8ef3abbd4adf27c29d8ceee205621339e2db4d3697392ea375e63ee484
7
+ data.tar.gz: 24379dc6fc1498860dadda55c13ebacf7bba1ccab4b9a058aad304eb22dbd2d64e7d10386e23f3f1d14912b11830c5dd23cd0c62f274f8e7f361a46ccb511cc7
data/.rubocop.yml CHANGED
@@ -30,3 +30,14 @@ Rails/Date:
30
30
 
31
31
  Rails/TimeZone:
32
32
  Enabled: false
33
+
34
+ Metrics/MethodLength:
35
+ Exclude:
36
+ - 'spec/**/*.rb'
37
+
38
+ Metrics/LineLength:
39
+ Exclude:
40
+ - 'spec/**/*.rb'
41
+
42
+ Style/WordArray:
43
+ Enabled: false
data/README.md CHANGED
@@ -143,6 +143,57 @@ contact.save!
143
143
  contact.update(linked_company_id: company.id)
144
144
  ```
145
145
 
146
+ ### Querying
147
+
148
+ Load by id
149
+
150
+ ```ruby
151
+ Amorail::Contact.find(223) #=> #<Amorail::Contact ...>
152
+ ```
153
+
154
+ Load many entites by array of ids
155
+
156
+ ```ruby
157
+ Amorail::Contact.find_all(123, 124) #=> [#<Amorail::Contact ...>, ...]
158
+ ```
159
+
160
+ Load by query
161
+
162
+ ```ruby
163
+ Amorail::Contact.find_by_query("my_company") #=> [#<Amorail::Contact ...>, ...]
164
+ ```
165
+
166
+
167
+ Load contacts associated with lead
168
+
169
+ ```ruby
170
+ lead = Amorail::Lead.find(1)
171
+ lead.contacts #=> [#<Amorail::Contact ...>, ...]
172
+ ```
173
+
174
+ Load company associated with contact
175
+
176
+ ```ruby
177
+ contact = Amorail::Contact.find(1)
178
+ contact.company #=> #<Amorail::Company ...>
179
+ ```
180
+
181
+ Load leads associated with contact
182
+
183
+ ```ruby
184
+ contact = Amorail::Contact.find(1)
185
+ contact.leads #=> [#<Amorail::Lead ...>, ...]
186
+ ```
187
+
188
+ Load contacts-leads pairs
189
+
190
+ ```ruby
191
+ # Load all contact-leads pairs for contacts
192
+ Amorail::ContactLink.find_by_contacts(1, 2)
193
+
194
+ # Load all contact-leads pairs for leads
195
+ Amorail::ContactLink.find_by_leads(1, 2)
196
+ ```
146
197
 
147
198
  ### Properties Configuration
148
199
 
@@ -14,6 +14,12 @@ module Amorail
14
14
 
15
15
  validates :name, presence: true
16
16
 
17
+ # Clear company cache
18
+ def reload
19
+ @company = nil
20
+ super
21
+ end
22
+
17
23
  def company
18
24
  return if linked_company_id.nil?
19
25
  @company ||= Amorail::Company.find(linked_company_id)
@@ -0,0 +1,32 @@
1
+ module Amorail
2
+ # AmoCRM contact-link join model
3
+ class ContactLink < Amorail::Entity
4
+ amo_names "contacts", "links"
5
+
6
+ amo_field :contact_id, :lead_id
7
+
8
+ class << self
9
+ # Find links by contacts ids
10
+ def find_by_contacts(*ids)
11
+ ids = ids.first if ids.size == 1 && ids.first.is_a?(Array)
12
+ response = Amorail.client.safe_request(
13
+ :get,
14
+ remote_url('links'),
15
+ contacts_link: ids
16
+ )
17
+ load_many(response)
18
+ end
19
+
20
+ # Find links by leads ids
21
+ def find_by_leads(*ids)
22
+ ids = ids.first if ids.size == 1 && ids.first.is_a?(Array)
23
+ response = Amorail.client.safe_request(
24
+ :get,
25
+ remote_url('links'),
26
+ deals_link: ids
27
+ )
28
+ load_many(response)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -6,5 +6,20 @@ module Amorail
6
6
  amo_field :name, :price, :status_id, :tags
7
7
 
8
8
  validates :name, :status_id, presence: true
9
+
10
+ def reload
11
+ @contacts = nil
12
+ super
13
+ end
14
+
15
+ # Return list of associated contacts
16
+ def contacts
17
+ fail NotPersisted if id.nil?
18
+ @contacts ||=
19
+ begin
20
+ links = Amorail::ContactLink.find_by_leads(id)
21
+ links.empty? ? [] : Amorail::Contact.find_all(links.map(&:contact_id))
22
+ end
23
+ end
9
24
  end
10
25
  end
@@ -1,14 +1,28 @@
1
1
  module Amorail
2
2
  # Lead associations
3
3
  module Leadable
4
- def linked_leads_id
5
- @linked_leads_id ||= []
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ amo_field :linked_leads_id
8
+ end
9
+
10
+ # Set initial value for linked_leads_id to []
11
+ def initialize(*args)
12
+ super
13
+ self.linked_leads_id ||= []
14
+ end
15
+
16
+ # Clear leads cache on reload
17
+ def reload
18
+ @leads = nil
19
+ super
6
20
  end
7
21
 
8
- def params
9
- data = super
10
- data[:linked_leads_id] = linked_leads_id unless linked_leads_id.empty?
11
- data
22
+ # Return all linked leads
23
+ def leads
24
+ return [] if linked_leads_id.empty?
25
+ @leads ||= Amorail::Lead.find_all(linked_leads_id)
12
26
  end
13
27
  end
14
28
  end
@@ -14,6 +14,17 @@ module Amorail # :nodoc: all
14
14
  rec
15
15
  end
16
16
 
17
+ def find_all(*ids)
18
+ ids = ids.first if ids.size == 1 && ids.first.is_a?(Array)
19
+
20
+ response = Amorail.client.safe_request(
21
+ :get,
22
+ remote_url('list'),
23
+ id: ids
24
+ )
25
+ load_many(response)
26
+ end
27
+
17
28
  # Find AMO entities by query
18
29
  # Returns array of matching entities.
19
30
  def find_by_query(q)
@@ -22,6 +33,12 @@ module Amorail # :nodoc: all
22
33
  remote_url('list'),
23
34
  query: q
24
35
  )
36
+ load_many(response)
37
+ end
38
+
39
+ private
40
+
41
+ def load_many(response)
25
42
  return [] unless response.status == 200
26
43
 
27
44
  (response.body['response'][amo_response_name] || [])
@@ -1,4 +1,4 @@
1
1
  # Amorail version
2
2
  module Amorail
3
- VERSION = "0.1.9"
3
+ VERSION = "0.2.0"
4
4
  end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe Amorail::ContactLink do
4
+ before { mock_api }
5
+
6
+ describe ".attributes" do
7
+ subject { described_class.attributes }
8
+
9
+ it_behaves_like 'entity_class'
10
+
11
+ specify do
12
+ is_expected.to include(
13
+ :contact_id,
14
+ :lead_id
15
+ )
16
+ end
17
+ end
18
+
19
+ describe ".find_by_leads" do
20
+ before { leads_links_stub(Amorail.config.api_endpoint, [2]) }
21
+
22
+ it "returns list of contact links" do
23
+ res = described_class.find_by_leads(2)
24
+ expect(res.size).to eq 2
25
+ expect(res.first.contact_id).to eq "101"
26
+ expect(res.last.contact_id).to eq "102"
27
+ end
28
+ end
29
+
30
+ describe ".find_by_contacts" do
31
+ before { contacts_links_stub(Amorail.config.api_endpoint, [101]) }
32
+
33
+ it "returns list of contact links" do
34
+ res = described_class.find_by_contacts(101)
35
+ expect(res.size).to eq 2
36
+ expect(res.first.lead_id).to eq "1"
37
+ expect(res.last.lead_id).to eq "2"
38
+ end
39
+ end
40
+ end
data/spec/contact_spec.rb CHANGED
@@ -78,6 +78,7 @@ describe Amorail::Contact do
78
78
  expect(obj.email).to eq "foo@tb.com"
79
79
  expect(obj.phone).to eq "1111 111 111"
80
80
  expect(obj.params[:id]).to eq 101
81
+ expect(obj.linked_leads_id).to contain_exactly("1872746", "1885024")
81
82
  end
82
83
 
83
84
  it "returns nil" do
@@ -113,6 +114,28 @@ describe Amorail::Contact do
113
114
  end
114
115
  end
115
116
 
117
+ describe ".find_all" do
118
+ before { contacts_find_all_stub(Amorail.config.api_endpoint, [101, 102]) }
119
+ before { contacts_find_all_stub(Amorail.config.api_endpoint, [105, 104], false) }
120
+
121
+ it "loads entities" do
122
+ res = described_class.find_all(101, 102)
123
+ expect(res.size).to eq 2
124
+ expect(res.first.id).to eq 101
125
+ expect(res.last.id).to eq 102
126
+ expect(res.first.company_name).to eq "Foo Inc."
127
+ expect(res.last.email).to eq "foo2@tb.com"
128
+ expect(res.first.phone).to eq "1111 111 111"
129
+ expect(res.first.params[:id]).to eq 101
130
+ end
131
+
132
+ it "returns empty array" do
133
+ res = described_class.find_all([105, 104])
134
+ expect(res).to be_a(Array)
135
+ expect(res).to be_empty
136
+ end
137
+ end
138
+
116
139
  describe "#save" do
117
140
  before { contact_create_stub(Amorail.config.api_endpoint) }
118
141
 
@@ -7,6 +7,10 @@
7
7
  "account_id": "8195968",
8
8
  "last_modified": 1423139130,
9
9
  "company_name": "Foo Inc.",
10
+ "linked_leads_id": [
11
+ "1872746",
12
+ "1885024"
13
+ ],
10
14
  "custom_fields":
11
15
  [
12
16
  {
@@ -0,0 +1,15 @@
1
+ {
2
+ "response": {
3
+ "links": [
4
+ {
5
+ "contact_id": "101",
6
+ "lead_id": "1",
7
+ "last_modified": 1374741830
8
+ },
9
+ {
10
+ "contact_id": "101",
11
+ "lead_id": "2",
12
+ "last_modified": 1374839942
13
+ }]
14
+ }
15
+ }
@@ -0,0 +1,69 @@
1
+ {
2
+ "response": {
3
+ "leads": [
4
+ {
5
+ "id": "1",
6
+ "name": "Research new technologies",
7
+ "last_modified": 1374656336,
8
+ "status_id": "7046196",
9
+ "price": "500000",
10
+ "responsible_user_id": "103586",
11
+ "tags":[
12
+ {
13
+ "id": "960472",
14
+ "name": "USA"},
15
+ {
16
+ "id": "960854",
17
+ "name": "Lead"
18
+ }
19
+ ],
20
+ "date_create": 1386014400,
21
+ "account_id": "7046192",
22
+ "created_user_id": "4502311",
23
+ "custom_fields": [
24
+ {
25
+ "id": "484604",
26
+ "name": "field",
27
+ "values": [
28
+ {
29
+ "value": "text"
30
+ }
31
+ ]
32
+ }
33
+ ]
34
+ },
35
+ {
36
+ "id": "2",
37
+ "name": "Sell it!",
38
+ "last_modified": 1374656336,
39
+ "status_id": "7046196",
40
+ "price": "100000",
41
+ "responsible_user_id": "103586",
42
+ "tags":[
43
+ {
44
+ "id": "960472",
45
+ "name": "USA"},
46
+ {
47
+ "id": "960854",
48
+ "name": "Lead"
49
+ }
50
+ ],
51
+ "date_create": 1386014400,
52
+ "account_id": "7046192",
53
+ "created_user_id": "4502311",
54
+ "custom_fields": [
55
+ {
56
+ "id": "484604",
57
+ "name": "field",
58
+ "values": [
59
+ {
60
+ "value": "text"
61
+ }
62
+ ]
63
+ }
64
+ ]
65
+ }
66
+ ],
67
+ "server_time": 1374839787
68
+ }
69
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "response": {
3
+ "links": [
4
+ {
5
+ "contact_id": "101",
6
+ "lead_id": "2",
7
+ "last_modified": 1374839942
8
+ },
9
+ {
10
+ "contact_id": "102",
11
+ "lead_id": "2",
12
+ "last_modified": 1374839942
13
+ }]
14
+ }
15
+ }
@@ -122,6 +122,24 @@ module AmoWebMock
122
122
  end
123
123
  end
124
124
 
125
+ def contacts_find_all_stub(endpoint, ids, success = true)
126
+ if success
127
+ stub_request(
128
+ :get,
129
+ "#{endpoint}/private/api/v2/json/contacts/list?#{ids.to_query('id')}")
130
+ .to_return(
131
+ body: File.read('./spec/fixtures/contact_find_query.json'),
132
+ headers: { 'Content-Type' => 'application/json' },
133
+ status: 200
134
+ )
135
+ else
136
+ stub_request(
137
+ :get,
138
+ "#{endpoint}/private/api/v2/json/contacts/list?#{ids.to_query('id')}")
139
+ .to_return(status: 204)
140
+ end
141
+ end
142
+
125
143
  def company_create_stub(endpoint)
126
144
  stub_request(:post, endpoint + '/private/api/v2/json/company/set')
127
145
  .to_return(
@@ -130,4 +148,45 @@ module AmoWebMock
130
148
  status: 200
131
149
  )
132
150
  end
151
+
152
+ def leads_stub(endpoint, ids, success = true)
153
+ if success
154
+ stub_request(
155
+ :get,
156
+ "#{endpoint}/private/api/v2/json/leads/list?#{ids.to_query('id')}")
157
+ .to_return(
158
+ body: File.read('./spec/fixtures/leads.json'),
159
+ headers: { 'Content-Type' => 'application/json' },
160
+ status: 200
161
+ )
162
+ else
163
+ stub_request(
164
+ :get,
165
+ "#{endpoint}/private/api/v2/json/leads/list?#{ids.to_query('id')}")
166
+ .to_return(status: 204)
167
+ end
168
+ end
169
+
170
+ def contacts_links_stub(endpoint, ids)
171
+ stub_request(:get, endpoint + "/private/api/v2/json/contacts/links?#{ids.to_query('contacts_link')}")
172
+ .to_return(
173
+ body: File.read('./spec/fixtures/contacts_links.json'),
174
+ headers: { 'Content-Type' => 'application/json' },
175
+ status: 200
176
+ )
177
+ end
178
+
179
+ def leads_links_stub(endpoint, ids, success = true)
180
+ if success
181
+ stub_request(:get, endpoint + "/private/api/v2/json/contacts/links?#{ids.to_query('deals_link')}")
182
+ .to_return(
183
+ body: File.read('./spec/fixtures/leads_links.json'),
184
+ headers: { 'Content-Type' => 'application/json' },
185
+ status: 200
186
+ )
187
+ else
188
+ stub_request(:get, endpoint + "/private/api/v2/json/contacts/links?#{ids.to_query('deals_link')}")
189
+ .to_return(status: 204)
190
+ end
191
+ end
133
192
  end
data/spec/lead_spec.rb CHANGED
@@ -41,4 +41,33 @@ describe Amorail::Lead do
41
41
  specify { is_expected.to include(status_id: 2) }
42
42
  specify { is_expected.to include(tags: 'test lead') }
43
43
  end
44
+
45
+ describe "#contacts" do
46
+ let(:lead) { described_class.new(id: 2) }
47
+
48
+ it "fails if not persisted" do
49
+ expect { described_class.new.contacts }
50
+ .to raise_error(Amorail::Entity::NotPersisted)
51
+ end
52
+
53
+ context "has contacts" do
54
+ before { leads_links_stub(Amorail.config.api_endpoint, [2]) }
55
+ before { contacts_find_all_stub(Amorail.config.api_endpoint, [101, 102]) }
56
+
57
+ it "loads contacts for lead" do
58
+ res = lead.contacts
59
+ expect(res.size).to eq 2
60
+ expect(res.first.id).to eq 101
61
+ expect(res.last.id).to eq 102
62
+ end
63
+ end
64
+
65
+ context "no contacts" do
66
+ before { leads_links_stub(Amorail.config.api_endpoint, [2], false) }
67
+
68
+ it "returns empty" do
69
+ expect(lead.contacts).to be_empty
70
+ end
71
+ end
72
+ end
44
73
  end
@@ -11,4 +11,23 @@ shared_examples 'leadable' do
11
11
  specify { is_expected.to include(:linked_leads_id) }
12
12
  specify { expect(subject.fetch(:linked_leads_id)).to include(100) }
13
13
  end
14
+
15
+ describe "#leads" do
16
+ before { leads_stub(Amorail.config.api_endpoint, [1, 2]) }
17
+
18
+ let(:leadable) { described_class.new(linked_leads_id: ['1', '2']) }
19
+
20
+ it "loads leads" do
21
+ expect(leadable.leads.size).to eq 2
22
+ expect(leadable.leads.first).to be_a(Amorail::Lead)
23
+ expect(leadable.leads.first.name).to eq "Research new technologies"
24
+ end
25
+
26
+ it "cache results" do
27
+ url = URI.join(Amorail.config.api_endpoint, Amorail::Lead.remote_url('list'))
28
+ leadable.leads
29
+ leadable.leads
30
+ expect(WebMock).to have_requested(:get, url).with(query: { id: [1, 2] }).once
31
+ end
32
+ end
14
33
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amorail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - alekseenkoss
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-10-27 00:00:00.000000000 Z
12
+ date: 2015-11-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -194,6 +194,7 @@ files:
194
194
  - lib/amorail/engine.rb
195
195
  - lib/amorail/entities/company.rb
196
196
  - lib/amorail/entities/contact.rb
197
+ - lib/amorail/entities/contact_link.rb
197
198
  - lib/amorail/entities/lead.rb
198
199
  - lib/amorail/entities/leadable.rb
199
200
  - lib/amorail/entities/task.rb
@@ -207,6 +208,7 @@ files:
207
208
  - lib/tasks/amorail.rake
208
209
  - spec/client_spec.rb
209
210
  - spec/company_spec.rb
211
+ - spec/contact_link_spec.rb
210
212
  - spec/contact_spec.rb
211
213
  - spec/entity_spec.rb
212
214
  - spec/fixtures/account_response.json
@@ -215,6 +217,9 @@ files:
215
217
  - spec/fixtures/contact_find.json
216
218
  - spec/fixtures/contact_find_query.json
217
219
  - spec/fixtures/contact_update.json
220
+ - spec/fixtures/contacts_links.json
221
+ - spec/fixtures/leads.json
222
+ - spec/fixtures/leads_links.json
218
223
  - spec/fixtures/my_contact_find.json
219
224
  - spec/helpers/webmock_helpers.rb
220
225
  - spec/lead_spec.rb
@@ -253,6 +258,7 @@ summary: Ruby API client for AmoCRM
253
258
  test_files:
254
259
  - spec/client_spec.rb
255
260
  - spec/company_spec.rb
261
+ - spec/contact_link_spec.rb
256
262
  - spec/contact_spec.rb
257
263
  - spec/entity_spec.rb
258
264
  - spec/fixtures/account_response.json
@@ -261,6 +267,9 @@ test_files:
261
267
  - spec/fixtures/contact_find.json
262
268
  - spec/fixtures/contact_find_query.json
263
269
  - spec/fixtures/contact_update.json
270
+ - spec/fixtures/contacts_links.json
271
+ - spec/fixtures/leads.json
272
+ - spec/fixtures/leads_links.json
264
273
  - spec/fixtures/my_contact_find.json
265
274
  - spec/helpers/webmock_helpers.rb
266
275
  - spec/lead_spec.rb