ctm 0.4.4 → 0.5.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.
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