forked from rabjohnston/E81ProjectPredictiveDialer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcallstats.py
More file actions
executable file
·169 lines (126 loc) · 6.3 KB
/
Copy pathcallstats.py
File metadata and controls
executable file
·169 lines (126 loc) · 6.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
from enum import Enum
from collections import OrderedDict
from datetime import datetime
import logging as log
CallState = Enum('CallState', ['created', 'ringing', 'answered', 'queued', 'talking', 'disconnected'])
class CallEvent:
def __init__(self, time, state):
self.time = time
self.state = state
class QueuedStats:
"""
CallStartDateTime, OutcomeCode, OffsetConnect, OffsetAgentRoute, OffsetDisconnect,
CallEndDateTime, UniqueId, CauseCode, QueuedStartDateTime, QueuedEndDateTime, Queued,
TransferredToAgent
"""
def __init__(self, callStartDateTime, outcome_code, offsetConnect, offsetDisconnect,
callEndDateTime, uniqueId, causeCode, queuedStartDateTime, queuedEndDateTime, queued,
transferredToAgent):
DATE_FORMAT = '%Y-%m-%d %H:%M:%S.%f'
TIME_TO_CREATE_CALL = 3000 # 3s to create a call
self._callStartDateTime = datetime.strptime(callStartDateTime, DATE_FORMAT)
self._callEndDateTime = datetime.strptime(callEndDateTime, DATE_FORMAT)
self.outcome_code = outcome_code
self._offsetConnect = offsetConnect
# We don't always get a disconnect offset - we can calculate one however..
if offsetDisconnect == 0:
self._offsetDisconnect = (self._callEndDateTime - self._callStartDateTime).microseconds / 1000
else:
self._offsetDisconnect = offsetDisconnect
self.unique_id = uniqueId
self._causeCode = causeCode
if( type(queuedStartDateTime) == str):
self._queuedStartDateTime = datetime.strptime(queuedStartDateTime, DATE_FORMAT)
if (type(queuedEndDateTime) == str):
self._queuedEndDateTime = datetime.strptime(queuedEndDateTime, DATE_FORMAT)
self._queued = queued == 1
self._transferredToAgent = transferredToAgent == 1
# The time it takes to generate a call.
self._offset_call_creation = TIME_TO_CREATE_CALL
# A list of all the events that will happen to this call
self._future_events = []
self._call_state = None
class CallStats:
"""
CallStartDateTime, OutcomeCode, OffsetConnect, OffsetAgentRoute, OffsetDisconnect,
CallEndDateTime, UniqueId, CauseCode, QueuedStartDateTime, QueuedEndDateTime, Queued,
TransferredToAgent
"""
def __init__(self, callStartDateTime, outcomeCode, offsetConnect, offsetDisconnect,
callEndDateTime, uniqueId, causeCode, queuedStartDateTime, queuedEndDateTime, queued,
transferredToAgent):
DATE_FORMAT = '%Y-%m-%d %H:%M:%S.%f'
TIME_TO_CREATE_CALL = 3000 # 3s to create a call
self._callStartDateTime = datetime.strptime(callStartDateTime, DATE_FORMAT)
self.outcome_code = outcomeCode
self._offsetConnect = offsetConnect
self._callEndDateTime = datetime.strptime(callEndDateTime, DATE_FORMAT)
self.unique_id = uniqueId
self._causeCode = causeCode
# We don't always get a disconnect offset - we can calculate one however..
if offsetDisconnect == 0:
self._offsetDisconnect = (self._callEndDateTime - self._callStartDateTime).total_seconds() * 1000
else:
self._offsetDisconnect = offsetDisconnect
if type(queuedStartDateTime) == str:
self._queuedStartDateTime = datetime.strptime(queuedStartDateTime, DATE_FORMAT)
if type(queuedEndDateTime) == str:
self._queuedEndDateTime = datetime.strptime(queuedEndDateTime, DATE_FORMAT)
self._queued = queued == 1
self._transferredToAgent = transferredToAgent == 1
# The time it takes to generate a call.
self._offset_call_creation = TIME_TO_CREATE_CALL
# A list of all the events that will happen to this call
self._future_events = []
self._call_state = None
self._birth_time = None
def dial(self, birth_time ):
self._birth_time = birth_time
self._call_state = CallState.created
self._future_events = []
self.calculate_future_events()
def talking(self, current_time):
"""
This call got answered and we're talking to an agent. Next thing is to stop talking...
:param current_time:
:return:
"""
self._future_events.append(CallEvent(current_time + self._offsetDisconnect, CallState.disconnected))
def queued(self, current_time, queued_call):
"""
This call has been queued. We calculate the disconnect time for the remote end to discinnect from the queue
if it doesn't get answered by an agent.
:param current_time:
:param queued_call:
:return:
"""
self._future_events.append(CallEvent(current_time + queued_call._offsetDisconnect, CallState.disconnected))
def calculate_future_events(self):
"""
Calculate all the state transitions and the time in which they will occur.
:return: Nothing
"""
# Handle the situation where the call doesn't get answered
if self.outcome_code in ['O', 'E', 'AM', 'NU', 'CF']:
self._future_events.append(CallEvent(self._birth_time + self._offset_call_creation, CallState.ringing))
self._future_events.append(CallEvent(self._birth_time + self._offsetDisconnect, CallState.disconnected))
# Handle the situation where the call is answered
elif self.outcome_code in ['TR', 'QD', 'QT', 'AC']:
self._future_events.append(CallEvent(self._birth_time + self._offset_call_creation, CallState.ringing))
self._future_events.append(CallEvent(self._birth_time + self._offsetDisconnect, CallState.answered))
else:
log.error('Unknown outcome: {}'.format(self.outcome_code))
def next_event(self, current_time):
"""
Respond to a tick. If we've got an event that has occurred then remove it from our
list of future events and return it to the caller.
:param current_time: the current time in the system
:return: the event, if we have one, otherwise None.
"""
if len(self._future_events) == 0:
return None
if self._future_events[0].time <= current_time:
ev = self._future_events.pop(0)
return ev
else:
return None