qmetrics 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +141 -0
- data/Rakefile +2 -0
- data/lib/qmetrics.rb +14 -0
- data/lib/qmetrics/api.rb +45 -0
- data/lib/qmetrics/caller.rb +63 -0
- data/lib/qmetrics/realtime.rb +12 -0
- data/lib/qmetrics/realtime_methods.yml +13 -0
- data/lib/qmetrics/response.rb +65 -0
- data/lib/qmetrics/stats.rb +20 -0
- data/lib/qmetrics/stats_methods.yml +86 -0
- data/lib/qmetrics/version.rb +3 -0
- data/qmetrics.gemspec +25 -0
- data/spec/lib/qmetrics/api_spec.rb +53 -0
- data/spec/lib/qmetrics/realtime_spec.rb +5 -0
- data/spec/lib/qmetrics/response_spec.rb +64 -0
- data/spec/lib/qmetrics/stats_spec.rb +7 -0
- data/spec/lib/qmetrics/version_spec.rb +8 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/api_config.rb +17 -0
- data/spec/support/realtime_config.rb +18 -0
- data/spec/support/shared_examples_for_caller.rb +46 -0
- data/spec/support/stats_config.rb +22 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ae3049cafee32758f34d294bb86246b8f9cc7bdd
|
4
|
+
data.tar.gz: ba4d97cca904ded5689436d108ce7375e08649c7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 02b65c3c6472a6958b21289462241211c8fac893d7cebdffdd85a383321a1141dfb3a52f80eabd409603337d804cdfb1e299f67d40d0c870cdbc63abf00ebaef
|
7
|
+
data.tar.gz: 56b07f2d90f474895da16e6fa24fef75c24dd85c856473db5ddfd55c21389b5dd27197984850bc337ad1e47c307fef35f2aaaef4297e5218e3500aaf93a7dd83
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Qmetrics
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.3
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Kevin Collette
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# Qmetrics
|
2
|
+
|
3
|
+
Qmetrics is a gem that wraps the Queuemetrics JSON API with Ruby!
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'qmetrics'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install qmetrics
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Note that this gem is unfinished! Things still need to be tweaked and tested.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
api = Qmetrics::API.new(server: 192.168.1.101, port: 80, user: "foo", pass: "bar")
|
27
|
+
api.stats(queue: [4343], from: Time.now-86400, to: Time.now)
|
28
|
+
|
29
|
+
p api.stats.all_calls.result
|
30
|
+
#=> #<Qmetrics::Response:0x007feac2bdada8 @status="OK", @description="", @time_elapsed="109ms", @qmetrics_version="14.06.2", @result={:all_calls=>{"All calls:"=>" ", "N. calls answered by operators:"=>"1,477", "Average call length:"=>"387.1 s.", "Min call length:"=>"0:00", "Max call length:"=>"1:22:45", "Total call length:"=>"158.8 H", "Average call waiting time:"=>"20.8 s.", "Min waiting time:"=>"0:01", "Max waiting time:"=>"7:54", "Total waiting time:"=>"8.6 H", "Average initial position"=>"1.5", "Min initial position"=>"1", "Max initial position"=>"7", "Coverage"=>"99.9%"}}
|
31
|
+
```
|
32
|
+
|
33
|
+
## Supported Methods
|
34
|
+
|
35
|
+
### Stats
|
36
|
+
|
37
|
+
- all_calls
|
38
|
+
- calls_within
|
39
|
+
- agents_on_queue
|
40
|
+
- service_level_agreement
|
41
|
+
- disconnection_causes
|
42
|
+
- transfers
|
43
|
+
- answered_calls_by_queue
|
44
|
+
- answered_calls_by_direction
|
45
|
+
- stints
|
46
|
+
- initial_queue_positions
|
47
|
+
- ivr_selections
|
48
|
+
- dnis
|
49
|
+
- music_on_hold_by_agent
|
50
|
+
- report_header
|
51
|
+
- answered_calls_details
|
52
|
+
- ivr_details
|
53
|
+
- all_unanswered_calls
|
54
|
+
- unanswered_calls_within
|
55
|
+
- disconnection_causes
|
56
|
+
- unanswered_by_queue
|
57
|
+
- unanswered_outbound_calls
|
58
|
+
- unanswered_by_length
|
59
|
+
- inclusive_sla
|
60
|
+
- unanswered_by_key_press
|
61
|
+
- unanswered_stints
|
62
|
+
- all_calls_by_stints
|
63
|
+
- all_calls_initial_queue_position
|
64
|
+
- lost_calls_ivr_selections
|
65
|
+
- all_calls_ivr_selections
|
66
|
+
- lost_calls_dnis
|
67
|
+
- all_calls_dnis
|
68
|
+
- call_overview
|
69
|
+
- inclusive_answered_sla
|
70
|
+
- unanswered_calls_details
|
71
|
+
- area_code_report
|
72
|
+
- answered_calls_by_area
|
73
|
+
- inbound_acd_call_attempts
|
74
|
+
- acd_attempts_by_queue
|
75
|
+
- acd_attempts_by_terminal
|
76
|
+
- answered_call_distribution_by_day
|
77
|
+
- answered_call_wait_time_per_day
|
78
|
+
- unanswered_call_wait_time_per_day
|
79
|
+
- sales_per_day
|
80
|
+
- schedule_adherence_per_day
|
81
|
+
- queue_length_per_day
|
82
|
+
- inclusive_sla_per_day
|
83
|
+
- traffic_analysis_per_day
|
84
|
+
- answered_call_distribution_per_hour
|
85
|
+
- answered_call_wait_time_per_hour
|
86
|
+
- unanswered_call_wait_time_per_hour
|
87
|
+
- sales_per_hour
|
88
|
+
- schedule_adherence_per_hour
|
89
|
+
- queue_length_per_hour
|
90
|
+
- inclusive_sla_per_hour
|
91
|
+
- traffic_analysis_per_hour
|
92
|
+
- answered_call_distribution_per_day_of_week
|
93
|
+
- answered_call_wait_time_per_day_of_week
|
94
|
+
- unanswered_call_wait_time_per_day_of_week
|
95
|
+
- sales_per_day_of_week
|
96
|
+
- schedule_adherence_per_day_of_week
|
97
|
+
- queue_length_per_day_of_week
|
98
|
+
- inclusive_sla_per_day_of_week
|
99
|
+
- traffic_analysis_per_day_of_week
|
100
|
+
- agent_session_detail
|
101
|
+
- session_and_pause_durations
|
102
|
+
- agent_availability
|
103
|
+
- answered_calls
|
104
|
+
- answered_calls_by_custom_group
|
105
|
+
- answered_calls_by_location
|
106
|
+
- answered_calls_by_service_group
|
107
|
+
- agent_performance_by_acd_group
|
108
|
+
- agent_occupancy_report
|
109
|
+
- agent_payable_time_by_hour
|
110
|
+
- agent_billable_time_by_hour
|
111
|
+
- detail_of_agent_pauses
|
112
|
+
- outcomes
|
113
|
+
- call_results_by_outcomes
|
114
|
+
- billable_activities
|
115
|
+
- non_billable_activities
|
116
|
+
- detailed_agent_report
|
117
|
+
- outcomes_per_agent
|
118
|
+
- ivr_traversals
|
119
|
+
- ivr_timing
|
120
|
+
- ivr_goals
|
121
|
+
|
122
|
+
### Realtime
|
123
|
+
|
124
|
+
- queues_in_use
|
125
|
+
- calls_being_processed
|
126
|
+
- agents_logged_in
|
127
|
+
- wallboard_top_panel
|
128
|
+
- wall_calls_being_processed
|
129
|
+
- visitor_calls_processed
|
130
|
+
- calls_taken
|
131
|
+
- calls_lost
|
132
|
+
- raw_agent_panel
|
133
|
+
- raw_calls_panel
|
134
|
+
|
135
|
+
## Contributing
|
136
|
+
|
137
|
+
1. Fork it ( https://github.com/[my-github-username]/Qmetrics/fork )
|
138
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
139
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
140
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
141
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/qmetrics.rb
ADDED
data/lib/qmetrics/api.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Qmetrics
|
2
|
+
class HTTPStatusError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class API
|
6
|
+
|
7
|
+
def initialize(server: , port: , user: , pass: )
|
8
|
+
@base_route = "http://#{server}:#{port}/queuemetrics"
|
9
|
+
@auth = { basic_auth: { username: user, password: pass } }
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(api_method,options={})
|
13
|
+
check_status(HTTParty.get("#{@base_route}/#{api_method}",
|
14
|
+
options.merge(@auth)))
|
15
|
+
end
|
16
|
+
|
17
|
+
def stats(**args)
|
18
|
+
if args.empty?
|
19
|
+
@stats
|
20
|
+
else
|
21
|
+
@stats = Qmetrics::Stats.new(args.merge({api: self}))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def realtime(**args)
|
26
|
+
if args.empty?
|
27
|
+
@realtime
|
28
|
+
else
|
29
|
+
@realtime = Qmetrics::Realtime.new(args.merge({api: self}))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def check_status(r)
|
36
|
+
if r.response.code == "200"
|
37
|
+
r.parsed_response
|
38
|
+
else
|
39
|
+
raise(HTTPStatusError, r.response.code)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Qmetrics
|
2
|
+
class Caller
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_reader :api_methods
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(queues: , api: )
|
9
|
+
@queues = queues
|
10
|
+
@api = api
|
11
|
+
clear_blocks
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(*args)
|
15
|
+
clear_blocks
|
16
|
+
args.each do |k|
|
17
|
+
@blocks.push(api_methods[k.to_sym]) if call_exists?(k.to_sym)
|
18
|
+
end
|
19
|
+
execute
|
20
|
+
end
|
21
|
+
|
22
|
+
# url encoded '|' to '%7C'
|
23
|
+
def to_s
|
24
|
+
"/jsonStatsApi.do?queues=#{@queues.join('%7C')}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.load_api_methods(file)
|
28
|
+
@api_methods ||= load_yml(file)
|
29
|
+
end
|
30
|
+
|
31
|
+
def api_methods
|
32
|
+
self.class.api_methods
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def self.load_yml(file)
|
38
|
+
YAML.load_file(File.join(File.dirname(__FILE__),file))
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.generate_api_methods
|
42
|
+
api_methods.each do |k, v|
|
43
|
+
define_method(k.to_sym) do
|
44
|
+
@blocks = [v]
|
45
|
+
execute
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute
|
51
|
+
Qmetrics::Response.new(@api.call(to_s),api_methods)
|
52
|
+
end
|
53
|
+
|
54
|
+
def call_exists?(call)
|
55
|
+
api_methods.keys.include? call
|
56
|
+
end
|
57
|
+
|
58
|
+
def clear_blocks
|
59
|
+
@blocks = []
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
---
|
2
|
+
:queues_in_use: "RealtimeDO.RTRiassunto"
|
3
|
+
:calls_being_processed: "RealtimeDO.RTCallsBeingProc"
|
4
|
+
:agents_logged_in: "RealtimeDO.RTAgentsLoggedIn"
|
5
|
+
:wallboard_top_panel: "RealtimeDO.WallRiassunto"
|
6
|
+
:wall_calls_being_processed: "RealtimeDO.WallCallsBeingProc"
|
7
|
+
:visitor_calls_processed: "RealtimeDO.VisitorCallsProc"
|
8
|
+
:calls_taken: "RealtimeDO.VisitorTodaysOk"
|
9
|
+
:calls_lost: "RealtimeDO.VisitorTodaysKo"
|
10
|
+
:raw_agent_panel: "RealtimeDO.RtAgentsRaw"
|
11
|
+
:raw_calls_panel: "RealtimeDO.RtCallsRaw"
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Qmetrics
|
2
|
+
class Response
|
3
|
+
attr_reader :status, :description, :time_elapsed, :qmetrics_version, :result
|
4
|
+
|
5
|
+
def initialize(qmetrics_result,api_methods)
|
6
|
+
@api_methods = api_methods
|
7
|
+
@status = qmetrics_result["result"][0][1]
|
8
|
+
@description = qmetrics_result["result"][1][1]
|
9
|
+
@time_elapsed = "#{qmetrics_result["result"][2][1]}ms"
|
10
|
+
@qmetrics_version = qmetrics_result["result"][3][1]
|
11
|
+
|
12
|
+
qmetrics_result.delete("result")
|
13
|
+
@result = zip_results(qmetrics_result)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def zip_results(qmetrics_result)
|
19
|
+
@result = {}
|
20
|
+
qmetrics_result.each do |k, v|
|
21
|
+
@result[translate_method_name(k)] = zip_arrs(v)
|
22
|
+
end
|
23
|
+
@result
|
24
|
+
end
|
25
|
+
|
26
|
+
def translate_method_name(java_method_name)
|
27
|
+
@api_methods.invert[java_method_name]
|
28
|
+
end
|
29
|
+
|
30
|
+
def zip_arrs(r)
|
31
|
+
r.first.size > 2 ? clean_output(zip_keys_and_values(r)) : hashify_pairs(r)
|
32
|
+
end
|
33
|
+
|
34
|
+
def zip_keys_and_values(results)
|
35
|
+
h = purge_entities_arr(results.first)
|
36
|
+
results[1..results.size].inject([]) do |a, v|
|
37
|
+
a.push(Hash[h.zip(purge_entities_arr(v))])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def clean_output(output)
|
42
|
+
output.map { |n| n.select { |k, v| !(junk_data?(k) && junk_data?(v)) } }
|
43
|
+
end
|
44
|
+
|
45
|
+
def hashify_pairs(results)
|
46
|
+
results.inject({}) do |a, v|
|
47
|
+
a.merge(purge_entities(v.first) => purge_entities(v.last))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def purge_entities_arr(values)
|
52
|
+
values.map {|n| purge_entities(n) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def purge_entities(value)
|
56
|
+
[' ', '<'].each{|t| value.gsub!(t,"")}
|
57
|
+
value.strip
|
58
|
+
end
|
59
|
+
|
60
|
+
def junk_data?(value)
|
61
|
+
["...","","-"].include? value
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Qmetrics
|
2
|
+
class Stats < Caller
|
3
|
+
load_api_methods("stats_methods.yml")
|
4
|
+
generate_api_methods
|
5
|
+
|
6
|
+
def initialize(from: , to: , **args)
|
7
|
+
super(args)
|
8
|
+
@from = from
|
9
|
+
@to = to
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"/QmStats" + super +
|
14
|
+
"&from=#{@from.strftime("%F.%H:%M:%S")}" \
|
15
|
+
"&to=#{@to.strftime("%F.%H:%M:%S")}" +
|
16
|
+
@blocks.map {|b| "&block=#{b}"}.join
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
---
|
2
|
+
:all_calls: "OkDO.RiassAllCalls"
|
3
|
+
:calls_within: "OkDO.RiassFullyWithin"
|
4
|
+
:agents_on_queue: "OkDO.AgentsOnQueue"
|
5
|
+
:service_level_agreement: "OkDO.ServiceLevelAgreement"
|
6
|
+
:disconnection_causes: "OkDO.DisconnectionCauses"
|
7
|
+
:transfers: "OkDO.Transfers"
|
8
|
+
:answered_calls_by_queue: "OkDO.AnsweredcallsByQueue"
|
9
|
+
:answered_calls_by_direction: "OkDO.AnsweredcallsByDirection"
|
10
|
+
:stints: "OkDO.StintsOk"
|
11
|
+
:initial_queue_positions: "OkDO.QPosOk"
|
12
|
+
:ivr_selections: "OkDO.IvrOk"
|
13
|
+
:dnis: "OkDO.DnisOk"
|
14
|
+
:music_on_hold_by_agent: "OkDO.MOHOk"
|
15
|
+
:report_header: "OkDO.HDRRpt"
|
16
|
+
:answered_calls_details: "DetailsDO.CallsOK"
|
17
|
+
:ivr_details: "DetailsDO.CallsIVR"
|
18
|
+
:all_unanswered_calls: "KoDO.ReportKoAll"
|
19
|
+
:unanswered_calls_within: "KoDO.ReportKoFully"
|
20
|
+
:disconnection_causes: "KoDO.DiscCauses"
|
21
|
+
:unanswered_by_queue: "KoDO.UnansByQueue"
|
22
|
+
:unanswered_outbound_calls: "KoDO.OutboundKo"
|
23
|
+
:unanswered_by_length: "KoDO.UnansByLen"
|
24
|
+
:inclusive_sla: "KoDO.InclusiveSLA"
|
25
|
+
:unanswered_by_key_press: "KoDO.ReportKoKeyPress"
|
26
|
+
:unanswered_stints: "KoDo.StintsKo"
|
27
|
+
:all_calls_by_stints: "KoDO.StintsOkKo"
|
28
|
+
:all_calls_initial_queue_position: "KoDO.QPosOkKo"
|
29
|
+
:lost_calls_ivr_selections: "KoDO.IvrKo"
|
30
|
+
:all_calls_ivr_selections: "KoDO.IvrOkKo"
|
31
|
+
:lost_calls_dnis: "KoDO.DnisKo"
|
32
|
+
:all_calls_dnis: "KoDO.DnisOkKo"
|
33
|
+
:call_overview: "KoDO.OverviewOkKo"
|
34
|
+
:inclusive_answered_sla: "KoDO.InclusiveAnswSLA"
|
35
|
+
:unanswered_calls_details: "DetailsDO.CallsKO"
|
36
|
+
:area_code_report: "AreaAnDO.Setup"
|
37
|
+
:answered_calls_by_area: "AreaAnDO.CallsKO"
|
38
|
+
:inbound_acd_call_attempts: "DistrDO.ReportAcd"
|
39
|
+
:acd_attempts_by_queue: "DistrDO.AcdByQueue"
|
40
|
+
:acd_attempts_by_terminal: "DistrDO.AcdByTerminals"
|
41
|
+
:answered_call_distribution_by_day: "CallDistrDO.AnsDistrPerDay"
|
42
|
+
:answered_call_wait_time_per_day: "CallDistrDO.AnsWaitPerDay"
|
43
|
+
:unanswered_call_wait_time_per_day: "CallDistrDO.UnansWaitPerDay"
|
44
|
+
:sales_per_day: "CallDistrDO.SalesPerDay"
|
45
|
+
:schedule_adherence_per_day: "CallDistrDO.StaffPerDay"
|
46
|
+
:queue_length_per_day: "CallDistrDO.QPosPerDay"
|
47
|
+
:inclusive_sla_per_day: "CallDistrDO.InclSlaPerDay"
|
48
|
+
:traffic_analysis_per_day: "CallDistrDO.TrafficAnPerDay"
|
49
|
+
:answered_call_distribution_per_hour: "CallDistrDO.AnsDistrPerHr"
|
50
|
+
:answered_call_wait_time_per_hour: "CallDistrDO.AnsWaitPerHr"
|
51
|
+
:unanswered_call_wait_time_per_hour: "CallDistrDO.UnansWaitPerHr"
|
52
|
+
:sales_per_hour: "CallDistrDO.SalesPerHr"
|
53
|
+
:schedule_adherence_per_hour: "CallDistrDO.StaffPerHr"
|
54
|
+
:queue_length_per_hour: "CallDistrDO.QPosPerHr"
|
55
|
+
:inclusive_sla_per_hour: "CallDistrDO.InclSlaPerHr"
|
56
|
+
:traffic_analysis_per_hour: "CallDistrDO.TrafficAnPerHr"
|
57
|
+
:answered_call_distribution_per_day_of_week: "CallDistrDO.AnsDistrPerDOW"
|
58
|
+
:answered_call_wait_time_per_day_of_week: "CallDistrDO.AnsWaitPerDOW"
|
59
|
+
:unanswered_call_wait_time_per_day_of_week: "CalldistrDO.UnansWaitPerDOW"
|
60
|
+
:sales_per_day_of_week: "CallDistrDO.SalesPerDOW"
|
61
|
+
:schedule_adherence_per_day_of_week: "CallDistrDO.StaffPerDOW"
|
62
|
+
:queue_length_per_day_of_week: "CallDistrDO.QPosPerDOW"
|
63
|
+
:inclusive_sla_per_day_of_week: "CallDistrDO.InclSlaPerDOW"
|
64
|
+
:traffic_analysis_per_day_of_week: "CallDistrDO.TrafficAnPerDOW"
|
65
|
+
:agent_session_detail: "AgentsDO.ReportAgents"
|
66
|
+
:session_and_pause_durations: "AgentsDO.SessionPauseDur"
|
67
|
+
:agent_availability: "AgentsDO.AgentAvail"
|
68
|
+
:answered_calls: "AgentsDO.AnsCallsQueues"
|
69
|
+
:answered_calls_by_custom_group: "AgentsDO.AnsCallsCG"
|
70
|
+
:answered_calls_by_location: "AgentsDO.AnsCallsLocation"
|
71
|
+
:answered_calls_by_service_group: "AgentsDO.AnsCallsSG"
|
72
|
+
:agent_performance_by_acd_group: "AgentsDO.PerformanceAcdGroups"
|
73
|
+
:agent_occupancy_report: "AgentsDO.AgentOccupancy"
|
74
|
+
:agent_payable_time_by_hour: "AgentsDO.AgentPayableTimeByHour"
|
75
|
+
:agent_billable_time_by_hour: "AgentsDO.AgentBillableTimeByHour"
|
76
|
+
:detail_of_agent_pauses: "DetailsDO.AgentPauses"
|
77
|
+
:outcomes: "OutcomesDO.GeneralRep"
|
78
|
+
:call_results_by_outcomes: "OutcomesDO.CallResByOutcome"
|
79
|
+
:billable_activities: "OutcomesDO.ActivBillable"
|
80
|
+
:non_billable_activities: "OutcomesDO.ActivNotBillable"
|
81
|
+
:detailed_agent_report: "OutcomesDO.AgentReportDetailed"
|
82
|
+
:outcomes_per_agent: "OutcomesDO.AgentOutcomes"
|
83
|
+
:ivr_traversals: "IvrDO.IvrReport"
|
84
|
+
:ivr_timing: "IvrDO.IvrTiming"
|
85
|
+
:ivr_goals: "IvrDO.IvrGoals"
|
86
|
+
|
data/qmetrics.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'qmetrics/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "qmetrics"
|
8
|
+
spec.version = Qmetrics::VERSION
|
9
|
+
spec.authors = ["Kevin Collette"]
|
10
|
+
spec.email = ["kevcollette@gmail.com"]
|
11
|
+
spec.summary = %q{A gem that wraps the Queuemetrics JSON API with Ruby}
|
12
|
+
spec.description = %q{}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.2.0"
|
24
|
+
spec.add_runtime_dependency "httparty", "~> 0.13.3"
|
25
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
describe Qmetrics::API do
|
2
|
+
|
3
|
+
let(:api) { Qmetrics::API.new(@api_config.to_h) }
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@api_config = APIConfig.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#new" do
|
10
|
+
it "should return a new Qmetrics::API object" do
|
11
|
+
expect(api).to be_a(Qmetrics::API)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#call" do
|
16
|
+
context "it is passed invalid auth credentials" do
|
17
|
+
|
18
|
+
it "should throw an exception" do
|
19
|
+
api_config = {server: @api_config.server,
|
20
|
+
port: @api_config.port,
|
21
|
+
user: "foo", pass: "bar" }
|
22
|
+
wrong_api = Qmetrics::API.new(api_config.to_h)
|
23
|
+
expect{wrong_api.call("agent/jsonEditorApi.do")}.to raise_exception("501")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "it is passed an invalid api method" do
|
28
|
+
it "should throw an exception" do
|
29
|
+
expect{api.call("agt/jsonEditorApi.do")}.to raise_exception("500")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "it is passed a valid Queuemetrics api method" do
|
34
|
+
it "should return an array" do
|
35
|
+
expect(api.call("agent/jsonEditorApi.do")).to be_an(Array)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#stats" do
|
42
|
+
let(:q_stats) { { queues: [1],
|
43
|
+
from: Time.now-86400,
|
44
|
+
to: Time.now } }
|
45
|
+
|
46
|
+
it "should return a Qmetrics::Stats object" do
|
47
|
+
expect(api.stats(q_stats)).to be_an_instance_of(Qmetrics::Stats)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
describe Qmetrics::Response do
|
2
|
+
|
3
|
+
let(:api) { Qmetrics::API.new(@api_config.to_h)}
|
4
|
+
let(:stats) { api.stats(@stats_config.to_h) }
|
5
|
+
let(:response) { stats.get(:stints,:answered_calls,:all_calls) }
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
@api_config = APIConfig.new
|
9
|
+
@stats_config = StatsConfig.new
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#result" do
|
13
|
+
it "should respond" do
|
14
|
+
expect{response.result}.not_to raise_exception
|
15
|
+
end
|
16
|
+
|
17
|
+
context "The result is for multiple agents" do
|
18
|
+
let(:result) { stats.answered_calls.result }
|
19
|
+
|
20
|
+
it "should be an Array of Hashes" do
|
21
|
+
expect(result[:answered_calls]).to be_an(Array)
|
22
|
+
expect(result[:answered_calls].first).to be_a(Hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
context "The result is for all agents" do
|
28
|
+
let(:result) { stats.all_calls.result }
|
29
|
+
|
30
|
+
it "should be a Hash" do
|
31
|
+
expect(result[:all_calls]).to be_a(Hash)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should remove HTML character entities from output" do
|
37
|
+
result = stats.agent_payable_time_by_hour.result
|
38
|
+
result[:agent_payable_time_by_hour].each do |n|
|
39
|
+
n.each do |k,v|
|
40
|
+
expect(k).to_not include(" ")
|
41
|
+
expect(v).to_not include(" ")
|
42
|
+
expect(k).to_not include("<")
|
43
|
+
expect(v).to_not include("<")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should remove superflous key-value pairs" do
|
49
|
+
result = stats.unanswered_calls_details.result
|
50
|
+
junk = ["...","-",""]
|
51
|
+
result[:unanswered_calls_details].each do |n|
|
52
|
+
n.each do |k,v|
|
53
|
+
if junk.include?(k)
|
54
|
+
expect(junk).not_to include(v)
|
55
|
+
elsif junk.include?(v)
|
56
|
+
expect(junk).not_to include(k)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class APIConfig
|
2
|
+
attr_reader :server, :port, :user, :pass
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@api_config = YAML.load_file(File.join(File.dirname(__FILE__),
|
6
|
+
"api_config.yml"))
|
7
|
+
@server = @api_config[:server]
|
8
|
+
@port = @api_config[:port]
|
9
|
+
@user = @api_config[:user]
|
10
|
+
@pass = @api_config[:pass]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
@api_config
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class RealtimeConfig
|
2
|
+
attr_reader :queues
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@realtime_config = YAML.load_file(File.join(File.dirname(__FILE__),
|
6
|
+
"realtime_config.yml"))
|
7
|
+
@api_config = APIConfig.new
|
8
|
+
@queues = @realtime_config[:queues]
|
9
|
+
@api = Qmetrics::API.new(@api_config.to_h)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h
|
13
|
+
@realtime_config[:api] = @api
|
14
|
+
@realtime_config
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
RSpec.shared_examples 'a Qmetrics::Caller' do |config_obj|
|
2
|
+
|
3
|
+
caller = described_class.new(config_obj.to_h)
|
4
|
+
|
5
|
+
describe "#api_methods" do
|
6
|
+
it "should exist" do
|
7
|
+
expect{caller.api_methods}.not_to raise_exception
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
caller.api_methods.each do |k, v|
|
12
|
+
describe "##{k}" do
|
13
|
+
before :all do
|
14
|
+
@response = caller.public_send(k)
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:response) { @response.dup }
|
18
|
+
|
19
|
+
it "should return an API Response" do
|
20
|
+
expect(response).to be_a(Qmetrics::Response)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return a response with the API call's key" do
|
24
|
+
expect(response.result).to have_key(k)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#get" do
|
30
|
+
let(:method) { caller.api_methods.first.first }
|
31
|
+
let(:method2) { caller.api_methods.take(2).last.first }
|
32
|
+
let(:response) { caller.get(method, method2) }
|
33
|
+
it "should return responses for all api methods passed to it." do
|
34
|
+
expect(response).to be_a(Qmetrics::Response)
|
35
|
+
expect(response.result).to have_key(method)
|
36
|
+
expect(response.result).to have_key(method2)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#to_s" do
|
41
|
+
it "should return a string" do
|
42
|
+
expect(caller.to_s).to be_a(String)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class StatsConfig
|
2
|
+
attr_reader :queues, :from, :to
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@stats_config = YAML.load_file(File.join(File.dirname(__FILE__),
|
6
|
+
"stats_config.yml"))
|
7
|
+
@api_config = APIConfig.new
|
8
|
+
@queues = @stats_config[:queues]
|
9
|
+
@from = Time.parse(@stats_config[:from])
|
10
|
+
@to = Time.parse(@stats_config[:to])
|
11
|
+
@api = Qmetrics::API.new(@api_config.to_h)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_h
|
15
|
+
@stats_config[:from] = @from
|
16
|
+
@stats_config[:to] = @to
|
17
|
+
@stats_config[:api] = @api
|
18
|
+
@stats_config
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: qmetrics
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kevin Collette
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.2.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.2.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httparty
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.13.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.13.3
|
69
|
+
description: ''
|
70
|
+
email:
|
71
|
+
- kevcollette@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".rspec"
|
78
|
+
- ".ruby-gemset"
|
79
|
+
- ".ruby-version"
|
80
|
+
- Gemfile
|
81
|
+
- LICENSE.txt
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- lib/qmetrics.rb
|
85
|
+
- lib/qmetrics/api.rb
|
86
|
+
- lib/qmetrics/caller.rb
|
87
|
+
- lib/qmetrics/realtime.rb
|
88
|
+
- lib/qmetrics/realtime_methods.yml
|
89
|
+
- lib/qmetrics/response.rb
|
90
|
+
- lib/qmetrics/stats.rb
|
91
|
+
- lib/qmetrics/stats_methods.yml
|
92
|
+
- lib/qmetrics/version.rb
|
93
|
+
- qmetrics.gemspec
|
94
|
+
- spec/lib/qmetrics/api_spec.rb
|
95
|
+
- spec/lib/qmetrics/realtime_spec.rb
|
96
|
+
- spec/lib/qmetrics/response_spec.rb
|
97
|
+
- spec/lib/qmetrics/stats_spec.rb
|
98
|
+
- spec/lib/qmetrics/version_spec.rb
|
99
|
+
- spec/spec_helper.rb
|
100
|
+
- spec/support/api_config.rb
|
101
|
+
- spec/support/realtime_config.rb
|
102
|
+
- spec/support/shared_examples_for_caller.rb
|
103
|
+
- spec/support/stats_config.rb
|
104
|
+
homepage: ''
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata: {}
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 2.2.2
|
125
|
+
signing_key:
|
126
|
+
specification_version: 4
|
127
|
+
summary: A gem that wraps the Queuemetrics JSON API with Ruby
|
128
|
+
test_files:
|
129
|
+
- spec/lib/qmetrics/api_spec.rb
|
130
|
+
- spec/lib/qmetrics/realtime_spec.rb
|
131
|
+
- spec/lib/qmetrics/response_spec.rb
|
132
|
+
- spec/lib/qmetrics/stats_spec.rb
|
133
|
+
- spec/lib/qmetrics/version_spec.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
- spec/support/api_config.rb
|
136
|
+
- spec/support/realtime_config.rb
|
137
|
+
- spec/support/shared_examples_for_caller.rb
|
138
|
+
- spec/support/stats_config.rb
|