ctm 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -11,115 +11,384 @@ Usage
11
11
  -----
12
12
 
13
13
  ```ruby
14
-
15
14
  require 'ctm'
16
15
 
17
- # get an access token
16
+ # Authentication
17
+
18
18
  access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
19
19
 
20
- # see the list of accounts
21
- puts CTM::Account.list(access_token).inspect
20
+ account = access_token.accounts.first
21
+ number = account.numbers.first
22
+
23
+ # Accounts
22
24
 
23
- # use this access token globally, instead of passing it to each method
24
- CTM::Auth.token = access_token
25
+ puts "Accounts you have access to (#{access_token.accounts.total_entries}):"
26
+ access_token.accounts.each do|a|
27
+ puts " #{a.name} -> #{a.status}, #{a.balance}"
28
+ end
29
+
30
+ puts
31
+ puts "Select an account:"
32
+ account = access_token.accounts.first
33
+ puts " First account: #{account.name}"
25
34
 
26
- # get my first account
27
- account = CTM::Account.first
35
+ account = access_token.accounts.find('name' => 'CallTrackingMetrics').first
36
+ puts " Found by name: #{account.name}"
28
37
 
29
- # get an account by name
30
- account = CTM::Account.find("name" => "My Account Name")
38
+ # Tracking Numbers
31
39
 
32
- # get a list of numbers within this account, returns 10 at a time by default
40
+ puts
33
41
  numbers = account.numbers
34
- puts numbers.first.inspect
35
- puts numbers.total_entries.inspect
36
- puts numbers.page.inspect
37
- puts numbers.per_page.inspect
38
- numbers.each {|number|
39
- puts number.id
40
- puts "#{number.name} #{number.number} -> #{number.formatted}"
41
- }
42
-
43
- # get the next 20 numbers on page 2
44
- numbers = account.numbers(:page => 2, :per_page => 20)
45
-
46
- # search for new numbers to purchase
47
- numbers = account.numbers.search("+1", :areacode => "410")
48
- numbers = account.numbers.search("+1", :tollfree => true, :areacode => "888")
49
- numbers = account.number.search("+44", :contains => "55")
50
-
51
- # purchase a new number
52
- number = account.numbers.buy(numbers.first.digits)
53
- if number.purchased?
54
- puts "successfully purchased the number: #{number.digits_formated}"
55
- else
56
- puts "failed to purchase that number"
42
+ puts "Tracking Numbers within the Account (#{numbers.total_entries}):"
43
+
44
+ puts " Page %-67s %-14s Formatted" % ["ID", "Number"]
45
+ numbers.each_with_index do|n, i|
46
+ break if i > 4
47
+ puts " %-4d %s %-14s %s" % [numbers.page, n.id, n.number, n.formatted]
48
+ end
49
+
50
+ puts ' ...'
51
+
52
+ numbers.page = numbers.total_pages
53
+ numbers.entries.reverse.each_with_index do|n, i|
54
+ break if i > 4
55
+ puts " %-4d %s %-14s %s" % [numbers.page, n.id, n.number, n.formatted]
56
+ end
57
+
58
+ puts
59
+ puts "Modify routing preferences"
60
+ [:round_robin, :least_connected, :simultaneous].each do |routing|
61
+ number.routing = routing
62
+ puts " #{number.formatted} currently uses #{number.routing} routing"
63
+ end
64
+
65
+ # Receiving Numbers
66
+
67
+ numbers = account.receiving_numbers
68
+ puts
69
+ puts "Receiving Numbers within the Account (#{numbers.total_entries}):"
70
+
71
+ puts " Page %-67s %-14s Formatted" % ["ID", "Number"]
72
+ numbers.each_with_index do|n, i|
73
+ break if i > 4
74
+ puts " %-4d %s %-14s %s" % [numbers.page, n.id, n.number, n.formatted]
75
+ end
76
+
77
+ puts ' ...'
78
+
79
+ numbers.page = numbers.total_pages
80
+ numbers.entries.reverse.each_with_index do|n, i|
81
+ break if i > 4
82
+ puts " %-4d %s %-14s %s" % [numbers.page, n.id, n.number, n.formatted]
57
83
  end
58
84
 
59
- # release the number, removing it from the account
60
- number.release!
85
+ receiving_number = account.receiving_numbers.create(
86
+ name: 'demo number', number: '+18008675309'
87
+ )
61
88
 
62
- # create a source from a predefined source
63
- source = account.sources.create(predefined: 'google_adwords')
89
+ puts
90
+ puts "Adding #{receiving_number.formatted}"
91
+ number.receiving_numbers.add receiving_number
64
92
 
65
- # list predefined sources
66
- predefined = account.predefined
93
+ puts "Receiving Numbers for #{number.formatted}"
94
+ number.receiving_numbers.each_page do |page|
95
+ page.each.map {|n| puts " #{n.formatted}"}
96
+ end
97
+
98
+ puts
99
+ puts "Removing #{receiving_number.formatted}"
100
+ number.receiving_numbers.rem receiving_number
101
+
102
+ puts "Receiving Numbers for #{number.formatted}"
103
+ number.receiving_numbers.each_page do |page|
104
+ page.each {|n| puts " #{n.formatted}"}
105
+ end
106
+
107
+ puts "Releasing #{number.formatted}"
108
+ receiving_number.release!
67
109
 
68
- # customize a source
69
- source = account.sources.find(:name => "Google Adwords")
70
- source.landing_url = "utm_campaign=MyCampaign"
71
- source.save
110
+ # Purchasing Numbers
72
111
 
73
- # assign a source to a number
74
- source.numbers.add(number)
112
+ puts
113
+ puts "Search for numbers to buy:"
75
114
 
76
- # get a list of receiving numbers
77
- receiving_numbers = account.receiving_numbers
115
+ puts " Country Region PostalCode TollFree Number"
116
+ matches = account.numbers.search("US", searchby: 'tollfree')
78
117
 
79
- # add a receiving number, note +1 country code is required
80
- receiving_number = account.receiving_numbers.create(name: "my number", number:"+15555555555")
118
+ total_tollfree = matches.total_entries
81
119
 
82
- # assign a receiving number to the tracking number
83
- number.receiving_numbers.add(receiving_number)
84
- # get the list of receiving numbers for this number
85
- puts number.receiving_numbers.inspect
86
- number.save
120
+ matches.each_with_index do |n, i|
121
+ break if i > 10
122
+ puts " %-7s %-6s %-10s %-8s %s" % [n.iso_country,
123
+ n.region, n.postal_code,
124
+ 'Yes', n.friendly_name]
125
+ end
126
+ puts ' ...'
87
127
 
88
- # modify the routing preference for the number
89
- number.routing = :simultaneous # :round_robin, :least_connected
90
- number.save
128
+ matches = account.numbers.search("US",
129
+ region: 'SC',
130
+ areacode: 910,
131
+ pattern: '802'
132
+ )
91
133
 
92
- # add a new user to the account
93
- account.users.create(first_name: 'First', last_name: 'Last', email: 'email@example.com', notify: true)
134
+ total_local = matches.total_entries
135
+
136
+ matches.each_with_index do |n,i|
137
+ break if i > 10
138
+ puts " %-7s %-6s %-10s %-8s %s" % [n.iso_country,
139
+ n.region, n.postal_code,
140
+ 'No', n.friendly_name]
141
+ end
142
+ puts ' ...'
143
+
144
+ puts
145
+ puts "Found #{total_local} local numbers."
146
+ puts "Found #{total_tollfree} toll-free numbers."
147
+
148
+ puts
149
+ puts "Purchase a number"
150
+ begin
151
+ number = account.numbers.buy matches.first.phone_number
152
+ puts "Successfully purchased the number: #{number.number}"
153
+
154
+ similar_numbers = account.numbers('number' => number.number)
155
+ puts " Search for active numbers matching %s gives %d results:" % [
156
+ number.number, similar_numbers.total_entries
157
+ ]
158
+ similar_numbers.each_page do |p| p.each {|n| puts " #{n.number}" }
159
+ end
160
+
161
+ number.release!
162
+ puts "Released number: #{number.number}"
163
+
164
+ similar_numbers = account.numbers('number' => number.number)
165
+ puts " Search for active numbers matching %s gives %d results:" % [
166
+ number.number, similar_numbers.total_entries
167
+ ]
168
+ similar_numbers.each_page do |p| p.each {|n| puts " #{n.number}" }
169
+ end
170
+
171
+ rescue CTM::Error::Buy => e
172
+ puts "Failed to purchase number (#{number.number}): #{e.message}"
173
+ end
174
+
175
+ # Tracking Sources
176
+
177
+ sources = account.sources
178
+
179
+ puts
180
+ puts "Tracking Sources within the Account (#{sources.total_entries})"
181
+ puts " Page %-5s %-30s Referring URL -> Landing URL" % ["ID","Name"]
182
+ 1.upto(sources.total_pages) do |page|
183
+ sources.page = page
184
+ sources.each do|source|
185
+ puts " %-4d %-5d %-30s '%s' -> '%s'" % [
186
+ sources.page, source.id,
187
+ source.name,
188
+ source.referring_url, source.landing_url]
189
+ end
190
+ end
191
+
192
+ src = account.sources.find(name: 'Direct').first
193
+ id = src.id
194
+
195
+ puts
196
+ puts "Customizing a source #{sources.filters.inspect}"
197
+
198
+ puts " Step %-5s %-30s Referring URL -> Landing URL" % ["ID","Name"]
199
+ puts " Find %-5d %-30s '%s' -> '%s'" % [src.id, src.name, src.referring_url, src.landing_url]
200
+
201
+ src.landing_url = "utm_campaign=DemoCampain"
202
+ src.referring_url = "some_search_engine.com"
203
+ src.name = "Demo Source"
204
+ puts " Change %-5d %-30s '%s' -> '%s'" % [src.id, src.name, src.referring_url, src.landing_url]
205
+
206
+ src.save
207
+ src = sources.get(id)
208
+ puts " Save %-5d %-30s '%s' -> '%s'" % [src.id, src.name, src.referring_url, src.landing_url]
209
+
210
+ src.landing_url = ""
211
+ src.referring_url = ""
212
+ src.name = "Direct"
213
+ src.save
214
+
215
+ puts " Revert %-5d %-30s '%s' -> '%s'" % [src.id, src.name, src.referring_url, src.landing_url]
216
+
217
+ # Users
94
218
 
95
- # list the users
96
219
  users = account.users
97
220
 
98
- # create a webhook to send call data at the start of the call
99
- account.webhooks.create(weburl: "http://myhost.com/new_calls", position: 'start')
221
+ puts
222
+ puts "Creating User with email: the.brave.johnny@example.com"
223
+ jbravo = users.create(
224
+ first_name: 'Johnny',
225
+ last_name: 'Bravo',
226
+ email: 'the.brave.johnny@example.com',
227
+ role: 'admin',
228
+ notify: false
229
+ ).id
230
+
231
+ puts
232
+ puts "Users within the Account (#{users.total_entries})"
233
+ puts " %-40s %-20s %-20s %s" % %w(ID Name Role Email)
234
+
235
+ users.each_page do |page|
236
+ page.each do|user|
237
+ puts " %-40s %-20s %-20s %s" % [user.id, user.name, user.role, user.email]
238
+ end
239
+ end
240
+
241
+ puts
242
+ puts "Removing User: %s" % [ account.users.get(jbravo).release!['status'] ]
100
243
 
101
- # create a webhook to send call data at the end of the call
102
- account.webhooks.create(weburl: "http://myhost.com/new_calls", position: 'end')
244
+ # Webhooks
103
245
 
104
- # list webhooks
105
- account.webhooks
246
+ ids = []
106
247
 
107
- # calls - list the calls
108
- account.calls
248
+ puts
249
+ puts "Creating webhook at start and end"
250
+ ids << account.webhooks.create(
251
+ weburl: "http://example.com/new_call/start",
252
+ position: 'start'
253
+ ).id
254
+
255
+ ids << account.webhooks.create(
256
+ weburl: "http://example.com/new_call/end",
257
+ position: 'end'
258
+ ).id
259
+
260
+ puts "Webhooks in account (#{account.webhooks.total_entries}):"
261
+ puts " %-5s Position WebURL" % ["ID"]
262
+ account.webhooks.each_page do |page|
263
+ page.each do |hook|
264
+ puts " %-5s %-8s %s" % [hook.id, hook.position, hook.weburl]
265
+ end
266
+ end
267
+
268
+ puts "Releasing webhooks"
269
+ ids.each do |i|
270
+ res = account.webhooks.get(i).release!
271
+
272
+ puts " %s: %s" % [ i, res['status'] == 'deleted' ? res['status'] : res.inspect ]
273
+ end
274
+
275
+ # Calls
109
276
 
110
277
  call = account.calls.first
278
+ call_fmt_str = " %-8s %-20s %-15s %-10s %-10s %-20s %-12s %-20s %-20s %s"
279
+
280
+ puts
281
+ puts "Call Information:"
282
+
283
+ puts call_fmt_str % %w(ID Source Likelihood TalkTime RingTime CalledAt DialStatus CallerNumber CallerName Notes)
284
+ puts call_fmt_str % [
285
+ call.id,
286
+ call.source, call.likelihood,
287
+ call.talk_time, call.ring_time,
288
+ call.called_at.split(' ')[0..1].join(' '), call.dial_status,
289
+ call.caller_number_format, call.name,
290
+ call.notes
291
+ ]
292
+
293
+ puts
294
+ puts "Adding note to call:"
295
+ old_note = call.notes
296
+ id = call.id
297
+ call.notes = "Test Note!"
298
+
299
+ puts call_fmt_str % %w(ID Source Likelihood TalkTime RingTime CalledAt
300
+ DialStatus CallerNumber CallerName Notes)
301
+ puts call_fmt_str % [
302
+ call.id,
303
+ call.source, call.likelihood,
304
+ call.talk_time, call.ring_time,
305
+ call.called_at.split(' ')[0..1].join(' '), call.dial_status,
306
+ call.caller_number_format, call.name,
307
+ call.notes
308
+ ]
111
309
 
112
- call.notes = "some notes to attach to the call"
113
310
  call.save
114
311
 
115
- # get sale record
116
- call.sale
312
+ call = account.calls.get id
313
+ puts
314
+ puts "Deleting note from call:"
315
+ puts call_fmt_str % %w(ID Source Likelihood TalkTime RingTime CalledAt
316
+ DialStatus CallerNumber CallerName Notes)
317
+ puts call_fmt_str % [
318
+ call.id,
319
+ call.source, call.likelihood,
320
+ call.talk_time, call.ring_time,
321
+ call.called_at.split(' ')[0..1].join(' '), call.dial_status,
322
+ call.caller_number_format, call.name,
323
+ call.notes
324
+ ]
325
+
326
+ call.notes = old_note
327
+ call.save
117
328
 
118
- # create sale record, marking the call as a conversion
119
- call.sale.create(name: "Who", score: 5, conversion: true, value: 34, date: '2013-04-24T00:00:00Z')
120
- # or update the sale record
121
- sale = call.sale
122
- sale.name = "Todd"
123
- sale.save
329
+ # Call Sale Record
330
+
331
+ old_sale = call.sale
332
+
333
+ sale_fmt_str = " %-10s %-10s %-15s %-5s %-5s %-10s"
334
+
335
+ puts
336
+ puts "Editing Sale on Call #{old_sale.call_id}"
337
+
338
+ puts sale_fmt_str % ['', *%w(Date CSR Score Value Converted?)]
339
+ puts sale_fmt_str % ['Existing',
340
+ old_sale.sale_date,
341
+ old_sale.name,
342
+ old_sale.score,
343
+ old_sale.value,
344
+ old_sale.conversion,
345
+ ]
346
+ call.sale.release!
347
+
348
+ new_sale = call.sale
349
+ puts sale_fmt_str % ['Deleted',
350
+ new_sale.sale_date,
351
+ new_sale.name,
352
+ new_sale.score,
353
+ new_sale.value,
354
+ new_sale.conversion,
355
+ ]
356
+
357
+ new_sale = call.sale
358
+ new_sale.name = 'The Doctor'
359
+ new_sale.score = 5
360
+ new_sale.conversion = true
361
+ new_sale.value = 12
362
+ new_sale.sale_date = Date.today.to_s
363
+
364
+ puts sale_fmt_str % ['Unsaved',
365
+ new_sale.sale_date,
366
+ new_sale.name,
367
+ new_sale.score,
368
+ new_sale.value,
369
+ new_sale.conversion,
370
+ ]
371
+
372
+ new_sale.save
373
+
374
+ new_sale = call.sale
375
+ puts sale_fmt_str % ['Refresh',
376
+ new_sale.sale_date,
377
+ new_sale.name,
378
+ new_sale.score,
379
+ new_sale.value,
380
+ new_sale.conversion,
381
+ ]
382
+
383
+ old_sale.save
384
+ new_sale = call.sale
385
+
386
+ puts sale_fmt_str % ['Restore',
387
+ new_sale.sale_date,
388
+ new_sale.name,
389
+ new_sale.score,
390
+ new_sale.value,
391
+ new_sale.conversion,
392
+ ]
124
393
 
125
394
  ```
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ctm"
3
- s.version = "0.4.4"
4
- s.authors = ["CallTrackingMetrics", "Todd Fisher"]
3
+ s.version = "0.5.0"
4
+ s.authors = ["CallTrackingMetrics", "Todd Fisher", "Morgen Peschke"]
5
5
  s.email = "info@calltrackingmetrics.com"
6
6
  s.files = `git ls-files`.split("\n")
7
7
  s.test_files = `git ls-files -- {test}/*`.split("\n")
@@ -17,4 +17,3 @@ Gem::Specification.new do |s|
17
17
  s.add_development_dependency 'fakeweb', '~> 1.3.0'
18
18
  s.add_development_dependency "rake"
19
19
  end
20
-
@@ -1,38 +1,380 @@
1
1
  $:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..", "lib")))
2
2
  require 'ctm'
3
3
 
4
+ # Authentication
5
+
4
6
  access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
5
- puts "Accounts you have access to:"
6
- access_token.accounts.each do|account|
7
- puts "#{account.name} -> #{account.status}, #{account.balance}, #{account.stats.inspect}"
7
+
8
+ account = access_token.accounts.first
9
+ number = account.numbers.first
10
+
11
+ # Accounts
12
+
13
+ puts "Accounts you have access to (#{access_token.accounts.total_entries}):"
14
+ access_token.accounts.each do|a|
15
+ puts " #{a.name} -> #{a.status}, #{a.balance}"
8
16
  end
17
+
18
+ puts
19
+ puts "Select an account:"
9
20
  account = access_token.accounts.first
21
+ puts " First account: #{account.name}"
10
22
 
23
+ account = access_token.accounts.find('name' => 'CallTrackingMetrics').first
24
+ puts " Found by name: #{account.name}"
25
+
26
+ # Tracking Numbers
27
+
28
+ puts
11
29
  numbers = account.numbers
12
- puts "Tracking Numbers #{numbers.total_entries} within the Account"
13
- numbers.each do|number|
14
- puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
30
+ puts "Tracking Numbers within the Account (#{numbers.total_entries}):"
31
+
32
+ puts " Page %-67s %-14s Formatted" % ["ID", "Number"]
33
+ numbers.each_with_index do|n, i|
34
+ break if i > 4
35
+ puts " %-4d %s %-14s %s" % [numbers.page, n.id, n.number, n.formatted]
36
+ end
37
+
38
+ puts ' ...'
39
+
40
+ numbers.page = numbers.total_pages
41
+ numbers.entries.reverse.each_with_index do|n, i|
42
+ break if i > 4
43
+ puts " %-4d %s %-14s %s" % [numbers.page, n.id, n.number, n.formatted]
44
+ end
45
+
46
+ puts
47
+ puts "Modify routing preferences"
48
+ [:round_robin, :least_connected, :simultaneous].each do |routing|
49
+ number.routing = routing
50
+ puts " #{number.formatted} currently uses #{number.routing} routing"
51
+ end
52
+
53
+ # Receiving Numbers
54
+
55
+ numbers = account.receiving_numbers
56
+ puts
57
+ puts "Receiving Numbers within the Account (#{numbers.total_entries}):"
58
+
59
+ puts " Page %-67s %-14s Formatted" % ["ID", "Number"]
60
+ numbers.each_with_index do|n, i|
61
+ break if i > 4
62
+ puts " %-4d %s %-14s %s" % [numbers.page, n.id, n.number, n.formatted]
63
+ end
64
+
65
+ puts ' ...'
66
+
67
+ numbers.page = numbers.total_pages
68
+ numbers.entries.reverse.each_with_index do|n, i|
69
+ break if i > 4
70
+ puts " %-4d %s %-14s %s" % [numbers.page, n.id, n.number, n.formatted]
71
+ end
72
+
73
+ receiving_number = account.receiving_numbers.create(
74
+ name: 'demo number', number: '+18008675309'
75
+ )
76
+
77
+ puts
78
+ puts "Adding #{receiving_number.formatted}"
79
+ number.receiving_numbers.add receiving_number
80
+
81
+ puts "Receiving Numbers for #{number.formatted}"
82
+ number.receiving_numbers.each_page do |page|
83
+ page.each.map {|n| puts " #{n.formatted}"}
84
+ end
85
+
86
+ puts
87
+ puts "Removing #{receiving_number.formatted}"
88
+ number.receiving_numbers.rem receiving_number
89
+
90
+ puts "Receiving Numbers for #{number.formatted}"
91
+ number.receiving_numbers.each_page do |page|
92
+ page.each {|n| puts " #{n.formatted}"}
93
+ end
94
+
95
+ puts "Releasing #{number.formatted}"
96
+ receiving_number.release!
97
+
98
+ # Purchasing Numbers
99
+
100
+ puts
101
+ puts "Search for numbers to buy:"
102
+
103
+ puts " Country Region PostalCode TollFree Number"
104
+ matches = account.numbers.search("US", searchby: 'tollfree')
105
+
106
+ total_tollfree = matches.total_entries
107
+
108
+ matches.each_with_index do |n, i|
109
+ break if i > 10
110
+ puts " %-7s %-6s %-10s %-8s %s" % [n.iso_country,
111
+ n.region, n.postal_code,
112
+ 'Yes', n.friendly_name]
15
113
  end
16
- receiving_numbers = account.receiving_numbers
17
- puts "Receiving Numbers #{receiving_numbers.total_entries} within the Account"
18
- receiving_numbers.each do|number|
19
- puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
114
+ puts ' ...'
115
+
116
+ matches = account.numbers.search("US",
117
+ region: 'SC',
118
+ areacode: 910,
119
+ pattern: '802'
120
+ )
121
+
122
+ total_local = matches.total_entries
123
+
124
+ matches.each_with_index do |n,i|
125
+ break if i > 10
126
+ puts " %-7s %-6s %-10s %-8s %s" % [n.iso_country,
127
+ n.region, n.postal_code,
128
+ 'No', n.friendly_name]
20
129
  end
130
+ puts ' ...'
131
+
132
+ puts
133
+ puts "Found #{total_local} local numbers."
134
+ puts "Found #{total_tollfree} toll-free numbers."
135
+
136
+ puts
137
+ puts "Purchase a number"
138
+ begin
139
+ number = account.numbers.buy matches.first.phone_number
140
+ puts "Successfully purchased the number: #{number.number}"
141
+
142
+ similar_numbers = account.numbers('number' => number.number)
143
+ puts " Search for active numbers matching %s gives %d results:" % [
144
+ number.number, similar_numbers.total_entries
145
+ ]
146
+ similar_numbers.each_page do |p| p.each {|n| puts " #{n.number}" }
147
+ end
148
+
149
+ number.release!
150
+ puts "Released number: #{number.number}"
151
+
152
+ similar_numbers = account.numbers('number' => number.number)
153
+ puts " Search for active numbers matching %s gives %d results:" % [
154
+ number.number, similar_numbers.total_entries
155
+ ]
156
+ similar_numbers.each_page do |p| p.each {|n| puts " #{n.number}" }
157
+ end
158
+
159
+ rescue CTM::Error::Buy => e
160
+ puts "Failed to purchase number (#{number.number}): #{e.message}"
161
+ end
162
+
163
+ # Tracking Sources
21
164
 
22
165
  sources = account.sources
23
- puts "Tracking Sources #{sources.total_entries} within the Account"
24
- sources.each do|source|
25
- puts "#{source.id}: #{source.name} #{source.referring_url} -> #{source.landing_url}"
166
+
167
+ puts
168
+ puts "Tracking Sources within the Account (#{sources.total_entries})"
169
+ puts " Page %-5s %-30s Referring URL -> Landing URL" % ["ID","Name"]
170
+ 1.upto(sources.total_pages) do |page|
171
+ sources.page = page
172
+ sources.each do|source|
173
+ puts " %-4d %-5d %-30s '%s' -> '%s'" % [
174
+ sources.page, source.id,
175
+ source.name,
176
+ source.referring_url, source.landing_url]
177
+ end
26
178
  end
27
179
 
180
+ src = account.sources.find(name: 'Direct').first
181
+ id = src.id
182
+
183
+ puts
184
+ puts "Customizing a source #{sources.filters.inspect}"
185
+
186
+ puts " Step %-5s %-30s Referring URL -> Landing URL" % ["ID","Name"]
187
+ puts " Find %-5d %-30s '%s' -> '%s'" % [src.id, src.name, src.referring_url, src.landing_url]
188
+
189
+ src.landing_url = "utm_campaign=DemoCampain"
190
+ src.referring_url = "some_search_engine.com"
191
+ src.name = "Demo Source"
192
+ puts " Change %-5d %-30s '%s' -> '%s'" % [src.id, src.name, src.referring_url, src.landing_url]
193
+
194
+ src.save
195
+ src = sources.get(id)
196
+ puts " Save %-5d %-30s '%s' -> '%s'" % [src.id, src.name, src.referring_url, src.landing_url]
197
+
198
+ src.landing_url = ""
199
+ src.referring_url = ""
200
+ src.name = "Direct"
201
+ src.save
202
+
203
+ puts " Revert %-5d %-30s '%s' -> '%s'" % [src.id, src.name, src.referring_url, src.landing_url]
204
+
205
+ # Users
206
+
28
207
  users = account.users
29
- puts "Users #{users.total_entries} within the Account"
30
- users.each do|user|
31
- puts "#{user.id}: #{user.name} #{user.email} -> #{user.role}"
208
+
209
+ puts
210
+ puts "Creating User with email: the.brave.johnny@example.com"
211
+ jbravo = users.create(
212
+ first_name: 'Johnny',
213
+ last_name: 'Bravo',
214
+ email: 'the.brave.johnny@example.com',
215
+ role: 'admin',
216
+ notify: false
217
+ ).id
218
+
219
+ puts
220
+ puts "Users within the Account (#{users.total_entries})"
221
+ puts " %-40s %-20s %-20s %s" % %w(ID Name Role Email)
222
+
223
+ users.each_page do |page|
224
+ page.each do|user|
225
+ puts " %-40s %-20s %-20s %s" % [user.id, user.name, user.role, user.email]
226
+ end
32
227
  end
33
228
 
34
- webhooks = account.webhooks
35
- puts "Webhooks #{webhooks.total_entries} within the Account"
36
- webhooks.each do|wh|
37
- puts "#{wh.id}: #{wh.weburl} #{wh.with_resource_url} -> #{wh.position}"
229
+ puts
230
+ puts "Removing User: %s" % [ account.users.get(jbravo).release!['status'] ]
231
+
232
+ # Webhooks
233
+
234
+ ids = []
235
+
236
+ puts
237
+ puts "Creating webhook at start and end"
238
+ ids << account.webhooks.create(
239
+ weburl: "http://example.com/new_call/start",
240
+ position: 'start'
241
+ ).id
242
+
243
+ ids << account.webhooks.create(
244
+ weburl: "http://example.com/new_call/end",
245
+ position: 'end'
246
+ ).id
247
+
248
+ puts "Webhooks in account (#{account.webhooks.total_entries}):"
249
+ puts " %-5s Position WebURL" % ["ID"]
250
+ account.webhooks.each_page do |page|
251
+ page.each do |hook|
252
+ puts " %-5s %-8s %s" % [hook.id, hook.position, hook.weburl]
253
+ end
254
+ end
255
+
256
+ puts "Releasing webhooks"
257
+ ids.each do |i|
258
+ res = account.webhooks.get(i).release!
259
+
260
+ puts " %s: %s" % [ i, res['status'] == 'deleted' ? res['status'] : res.inspect ]
38
261
  end
262
+
263
+ # Calls
264
+
265
+ call = account.calls.first
266
+ call_fmt_str = " %-8s %-20s %-15s %-10s %-10s %-20s %-12s %-20s %-20s %s"
267
+
268
+ puts
269
+ puts "Call Information:"
270
+
271
+ puts call_fmt_str % %w(ID Source Likelihood TalkTime RingTime CalledAt DialStatus CallerNumber CallerName Notes)
272
+ puts call_fmt_str % [
273
+ call.id,
274
+ call.source, call.likelihood,
275
+ call.talk_time, call.ring_time,
276
+ call.called_at.split(' ')[0..1].join(' '), call.dial_status,
277
+ call.caller_number_format, call.name,
278
+ call.notes
279
+ ]
280
+
281
+ puts
282
+ puts "Adding note to call:"
283
+ old_note = call.notes
284
+ id = call.id
285
+ call.notes = "Test Note!"
286
+
287
+ puts call_fmt_str % %w(ID Source Likelihood TalkTime RingTime CalledAt
288
+ DialStatus CallerNumber CallerName Notes)
289
+ puts call_fmt_str % [
290
+ call.id,
291
+ call.source, call.likelihood,
292
+ call.talk_time, call.ring_time,
293
+ call.called_at.split(' ')[0..1].join(' '), call.dial_status,
294
+ call.caller_number_format, call.name,
295
+ call.notes
296
+ ]
297
+
298
+ call.save
299
+
300
+ call = account.calls.get id
301
+ puts
302
+ puts "Deleting note from call:"
303
+ puts call_fmt_str % %w(ID Source Likelihood TalkTime RingTime CalledAt
304
+ DialStatus CallerNumber CallerName Notes)
305
+ puts call_fmt_str % [
306
+ call.id,
307
+ call.source, call.likelihood,
308
+ call.talk_time, call.ring_time,
309
+ call.called_at.split(' ')[0..1].join(' '), call.dial_status,
310
+ call.caller_number_format, call.name,
311
+ call.notes
312
+ ]
313
+
314
+ call.notes = old_note
315
+ call.save
316
+
317
+ # Call Sale Record
318
+
319
+ old_sale = call.sale
320
+
321
+ sale_fmt_str = " %-10s %-10s %-15s %-5s %-5s %-10s"
322
+
323
+ puts
324
+ puts "Editing Sale on Call #{old_sale.call_id}"
325
+
326
+ puts sale_fmt_str % ['', *%w(Date CSR Score Value Converted?)]
327
+ puts sale_fmt_str % ['Existing',
328
+ old_sale.sale_date,
329
+ old_sale.name,
330
+ old_sale.score,
331
+ old_sale.value,
332
+ old_sale.conversion,
333
+ ]
334
+ call.sale.release!
335
+
336
+ new_sale = call.sale
337
+ puts sale_fmt_str % ['Deleted',
338
+ new_sale.sale_date,
339
+ new_sale.name,
340
+ new_sale.score,
341
+ new_sale.value,
342
+ new_sale.conversion,
343
+ ]
344
+
345
+ new_sale = call.sale
346
+ new_sale.name = 'The Doctor'
347
+ new_sale.score = 5
348
+ new_sale.conversion = true
349
+ new_sale.value = 12
350
+ new_sale.sale_date = Date.today.to_s
351
+
352
+ puts sale_fmt_str % ['Unsaved',
353
+ new_sale.sale_date,
354
+ new_sale.name,
355
+ new_sale.score,
356
+ new_sale.value,
357
+ new_sale.conversion,
358
+ ]
359
+
360
+ new_sale.save
361
+
362
+ new_sale = call.sale
363
+ puts sale_fmt_str % ['Refresh',
364
+ new_sale.sale_date,
365
+ new_sale.name,
366
+ new_sale.score,
367
+ new_sale.value,
368
+ new_sale.conversion,
369
+ ]
370
+
371
+ old_sale.save
372
+ new_sale = call.sale
373
+
374
+ puts sale_fmt_str % ['Restore',
375
+ new_sale.sale_date,
376
+ new_sale.name,
377
+ new_sale.score,
378
+ new_sale.value,
379
+ new_sale.conversion,
380
+ ]
@@ -5,6 +5,6 @@ require 'set'
5
5
  access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
6
6
  account = access_token.accounts.first
7
7
 
8
- call = account.calls.get(692389)
8
+ call = account.calls.get(3446138)
9
9
 
10
10
  call.record_sale({value:100, conversion: true})
@@ -5,7 +5,7 @@ module CTM
5
5
 
6
6
  def initialize(data, token=nil)
7
7
  super(data, token)
8
- puts data.inspect
8
+ #puts data.inspect
9
9
  @id = data['id']
10
10
  @name = data['name']
11
11
  @status = data['status']
@@ -1,7 +1,7 @@
1
1
  module CTM
2
2
  class Auth
3
3
  include HTTParty
4
- base_uri ENV["CTM_URL"] || "api.calltrackingmetrics.com"
4
+ base_uri "https://#{(ENV["CTM_URL"] || "api.calltrackingmetrics.com")}"
5
5
 
6
6
  def self.token=(token)
7
7
  @token = token
@@ -12,7 +12,7 @@ module CTM
12
12
  end
13
13
 
14
14
  include HTTParty
15
- base_uri ENV["CTM_URL"] || "api.calltrackingmetrics.com"
15
+ base_uri "https://#{(ENV["CTM_URL"] || "api.calltrackingmetrics.com")}"
16
16
 
17
17
  attr_reader :token, :account_id
18
18
 
@@ -20,7 +20,11 @@ module CTM
20
20
  def initialize(data, token=nil)
21
21
  @token = token || CTM::Auth.token
22
22
  @account_id = data['account_id']
23
- @list_token_type = self.class.to_s.sub(/CTM::/,'').underscore.pluralize
23
+ @list_token_type = case self.class.to_s
24
+ when 'CTM::Sale' then 'calls'
25
+ else
26
+ self.class.to_s.sub(/CTM::/,'').underscore.pluralize
27
+ end
24
28
  if @account_id
25
29
  @list_type_path = "accounts/#{@account_id}/#{@list_token_type}"
26
30
  else
@@ -29,15 +33,16 @@ module CTM
29
33
  end
30
34
 
31
35
  def save(options={})
32
- puts "save: #{options.inspect}"
36
+ #puts "save: #{options.inspect}"
33
37
  path_str = "/api/v1/#{@list_type_path}/#{@id}.json"
34
- puts path_str
35
- res = self.class.put(path_str, :body => options.merge(:auth_token => @token))
38
+ #puts path_str
39
+ self.class.put(path_str, :body => options.merge(:auth_token => @token))
36
40
  end
37
41
 
38
42
  def release!
39
43
  path_str = "/api/v1/#{@list_type_path}/#{@id}.json"
40
44
  res = self.class.delete(path_str, :body => {:auth_token => @token})
45
+ res.parsed_response
41
46
  end
42
47
 
43
48
  def self.create(options)
@@ -46,10 +51,10 @@ module CTM
46
51
  account_id = options.delete(:account_id)
47
52
  token = options.delete(:token)
48
53
  path_str = "/api/v1/#{list_type_path}.json"
49
- puts "create: #{self}(#{path_str}) -> #{options.inspect}"
54
+ #puts "create: #{self}(#{path_str}) -> #{options.inspect}"
50
55
  res = self.post(path_str, :body => options.merge(:auth_token => token))
51
- puts "result: #{res.parsed_response.inspect}"
52
- puts "properties: #{list_type_path.inspect} -> #{list_token_type.inspect} -> #{account_id}"
56
+ #puts "result: #{res.parsed_response.inspect}"
57
+ #puts "properties: #{list_type_path.inspect} -> #{list_token_type.inspect} -> #{account_id}"
53
58
  if res.parsed_response['status'] == 'error'
54
59
  raise CTM::Error::Create.new(res.parsed_response['reason'])
55
60
  else
@@ -4,12 +4,12 @@ module CTM
4
4
  :id, :account_id, :search, :referrer, :location, :source,
5
5
  :likelihood, :duration, :talk_time, :ring_time, :called_at, :tracking_number, :business_number,
6
6
  :dial_status, :caller_number_split, :excluded, :tracking_number_format, :business_number_format,
7
- :caller_number_format, :audio, :tag_list, :latitude, :longitude, :extended_lookup, :sale
7
+ :caller_number_format, :audio, :tag_list, :latitude, :longitude, :extended_lookup
8
8
  ]
9
9
  ReadWriteFields = [
10
10
  :name, :email, :street, :city, :state, :country, :postal_code, :notes
11
11
  ]
12
- attr_reader *ReadOnlyFields
12
+ attr_reader *ReadOnlyFields
13
13
  attr_accessor *ReadWriteFields
14
14
 
15
15
  # {"id":729485,"account_id":25,"name":"Escondido Ca","search":null,"referrer":null,"location":null,"source":"Facebook","source_id":36,"likelihood":null,"duration":25,
@@ -29,20 +29,33 @@ module CTM
29
29
  end
30
30
  end
31
31
 
32
- def record_sale(sale_detail)
33
- path_str = "/api/v1/#{@list_type_path}/#{self.id}/sale.json"
34
- post_options = {}
35
- sale_detail.each do|k,v|
36
- if k.to_s == 'conversion'
37
- v = v ? 'on' : 'off'
38
- end
39
- post_options[k] = v
32
+ def save(options={})
33
+ #puts "save: #{options.inspect}"
34
+ path_str = "/api/v1/#{@list_type_path}/#{@id}/modify.json"
35
+
36
+ save_options = {}
37
+ ReadWriteFields.each do |field|
38
+ save_options[field == :notes ? :comments : field] = self.send field
40
39
  end
41
- res = self.class.post(path_str, :body => post_options.merge(:auth_token => @token))
42
- (res && res['status'] == 'success')
40
+
41
+ options[:call] = (options[:call] || {}).merge save_options
42
+
43
+ #puts path_str
44
+ self.class.put(path_str, :body => options.merge(:auth_token => @token))
43
45
  end
44
46
 
45
- def update_sale(sale_detail)
47
+ def sale
48
+ path_str = "/api/v1/#{@list_type_path}/#{self.id}/sale.json"
49
+
50
+ res = self.class.get path_str, query: {auth_token: @token}
51
+ data = res.parsed_response
52
+ if data["status"] && data["status"] == "error"
53
+ raise CTM::Error::Sale.new(data["message"] || data ["reason"])
54
+ end
55
+
56
+ data['account_id'] = @account_id
57
+ data['call_id'] ||= self.id
58
+ CTM::Sale.new(data, @token)
46
59
  end
47
60
 
48
61
  end
@@ -12,5 +12,7 @@ module CTM
12
12
  end
13
13
  class Rem < Exception
14
14
  end
15
+ class Sale < Exception
16
+ end
15
17
  end
16
18
  end
@@ -4,9 +4,12 @@ module CTM
4
4
  include Enumerable
5
5
 
6
6
  include HTTParty
7
- base_uri ENV["CTM_URL"] || "api.calltrackingmetrics.com"
7
+ base_uri "https://#{(ENV["CTM_URL"] || "api.calltrackingmetrics.com")}"
8
8
 
9
- attr_reader :list_type, :token, :per_page, :page, :total_entries, :objects
9
+ attr_reader :list_type, :token, :total_entries, :objects
10
+ attr_reader :per_page, :page, :total_pages
11
+
12
+ attr_reader :filters
10
13
 
11
14
  # e.g. Account, token
12
15
  def initialize(list_type, options={}, token=nil, fetched_objects=nil)
@@ -23,16 +26,32 @@ module CTM
23
26
 
24
27
  @fetched_objects = fetched_objects
25
28
  @options = options
29
+ @filters = {}
30
+ load_records
31
+ end
32
+
33
+ def page=(num)
34
+ @options[:page] = num.to_i
35
+ fetch_page(@options) unless @options[:page] == @page
36
+ @page
26
37
  end
27
38
 
28
- def each &block
39
+ def each_page
40
+ # Trick to allow .each_page.each_with_index from:
41
+ # http://stackoverflow.com/a/18089712
42
+ return to_enum(:each_page) unless block_given?
43
+
44
+ 1.upto(@total_pages) do |pnum|
45
+ self.page = pnum
46
+ yield self
47
+ end
48
+ end
49
+
50
+ def each
51
+ return to_enum(:each) unless block_given?
29
52
  load_records
30
53
  @objects.each do |obj|
31
- if block_given?
32
- block.call obj
33
- else
34
- yield obj
35
- end
54
+ yield obj
36
55
  end
37
56
  end
38
57
 
@@ -43,12 +62,16 @@ module CTM
43
62
  token: @token))
44
63
  end
45
64
 
46
- def find(options)
65
+ def find(options = {})
66
+ return self unless options.class == Hash
67
+
47
68
  first_name = options.delete(:first_name)
48
69
  last_name = options.delete(:last_name)
49
70
  options[:filter] = options.delete(:filter) || "#{first_name} #{last_name}".strip if first_name || last_name
50
71
 
51
- fetch_page(options)
72
+ @filters = options
73
+
74
+ self.page = 1
52
75
  self
53
76
  end
54
77
 
@@ -56,7 +79,7 @@ module CTM
56
79
  path_str = "/api/v1/#{@list_type_path}/#{recordid}.json"
57
80
  res = self.class.get(path_str, query: options.merge(auth_token: @token))
58
81
  data = res.parsed_response
59
- @object_klass.new(data, @token)
82
+ @object_klass.new(data, @token)
60
83
  end
61
84
 
62
85
  protected
@@ -70,7 +93,7 @@ module CTM
70
93
  end
71
94
 
72
95
  def fetch_page(options={})
73
- options = {per_page: 10, page: 1}.merge(options)
96
+ options = {per_page: 10, page: 1}.merge(options).merge(@filters)
74
97
  path_str = "/api/v1/#{@list_type_path}.json"
75
98
  res = self.class.get(path_str, query: options.merge(auth_token: @token))
76
99
  data = res.parsed_response
@@ -78,15 +101,17 @@ module CTM
78
101
  puts data.inspect
79
102
  raise CTM::Error::List.new(data["message"] || data["reason"])
80
103
  end
104
+
105
+ @page = options[:page]
106
+ @per_page = options[:per_page]
81
107
  map_data(data)
82
108
  end
83
109
 
84
110
  def map_data(data)
85
- @page = data['page']
86
- @per_page = data['per_page']
87
111
  @total_entries = data['total_entries']
112
+ @total_pages = data['total_pages']
88
113
  @objects = data[@list_token_type].map {|obj|
89
- @object_klass.new(obj, @token)
114
+ @object_klass.new(obj, @token)
90
115
  }
91
116
  end
92
117
 
@@ -42,7 +42,7 @@ module CTM
42
42
  # add trackng number to tracking source
43
43
  def add(number)
44
44
  path_str = "/api/v1/#{@list_type_path}/#{number.id}/add.json"
45
- puts "Add to #{@account_id}:#{@source_id} -> #{number.id} -> #{path_str}"
45
+ #puts "Add to #{@account_id}:#{@source_id} -> #{number.id} -> #{path_str}"
46
46
  # accounts/25 /sources/5012 /numbers
47
47
  # /api/v1/accounts/:account_id/sources/:source_id/numbers/:id/add
48
48
  res = self.class.post(path_str, :body => {}.merge(:auth_token => @token))
@@ -54,10 +54,10 @@ module CTM
54
54
  end
55
55
  end
56
56
 
57
- def rem
58
- puts "Rem to #{@account_id}:#{@source_id} -> #{number.id} -> #{@list_type_path}"
59
- # /api/v1/accounts/:account_id/sources/:source_id/numbers/:id/rem
60
- end
57
+ # def rem(number)
58
+ # puts "Rem to #{@account_id}:#{@source_id} -> #{number.id} -> #{@list_type_path}"
59
+ # # /api/v1/accounts/:account_id/sources/:source_id/numbers/:id/rem
60
+ # end
61
61
 
62
62
  end
63
63
  end
@@ -1,7 +1,53 @@
1
1
  module CTM
2
- class Sale
2
+ class Sale < Base
3
+ ReadWriteFields = [:conversion,
4
+ :sale_date, :score,
5
+ :service_rep_name, :value]
3
6
 
4
- def initialize
7
+ attr_reader :call_id
8
+ attr_accessor(*ReadWriteFields)
9
+
10
+ def initialize(data, token=nil)
11
+ super(data, token)
12
+
13
+ [ :call_id, *ReadWriteFields].each do |k|
14
+ instance_variable_set "@#{k}", data[k.to_s]
15
+ end
16
+ end
17
+
18
+ def name
19
+ @service_rep_name
20
+ end
21
+
22
+ def name=(n)
23
+ @service_rep_name = n
24
+ @service_rep_name
25
+ end
26
+
27
+ def release!
28
+ path_str ="/api/v1/#{@list_type_path}/#{@call_id}/sale.json"
29
+ res = self.class.delete path_str, body: {auth_token: @token}
30
+ res.parsed_response
31
+ end
32
+
33
+ def save(options = {})
34
+ path_str = "/api/v1/#{@list_type_path}/#{@call_id}/sale.json"
35
+ options = {}
36
+ ReadWriteFields.each do |k|
37
+ v = self.send k
38
+ case k.to_s
39
+ when 'conversion' then v = v ? 'on' : 'off'
40
+ when 'service_rep_name' then k = :name
41
+ end
42
+ options[k] = v
43
+ end
44
+ options[:id] = @call_id
45
+
46
+ #self.class.debug_output $stderr
47
+ res = self.class.post path_str, body: options.merge(auth_token: @token)
48
+ #self.class.debug_output nil
49
+ return nil unless res
50
+ (res['status'] == 'success') ? true : (res['message'] || res['reason'])
5
51
  end
6
52
 
7
53
  end
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ctm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - CallTrackingMetrics
9
9
  - Todd Fisher
10
+ - Morgen Peschke
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2013-08-05 00:00:00.000000000 Z
14
+ date: 2014-05-01 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: phony