Commit db3c81d76337f9a49a88265f2da2b42594cc2712
Readability counts.
Breaking lines longer than 80.
Minutes of a call should be counted after the user has answered the call
not since the call has been started. This value is stored in the billsec
column of cdr table.
Answered calls should be counted when there is a disposition of
answered, likewise for unanswered calls.
Count number of calls which went unaccounted for, as in failed/busy/no
answer with dcontext as default.
- query.py 82 ---------------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- report.py 8 ---+++++
| | | | 21 | self.t.lt.posted.between(date, dateRange)).count() | 21 | self.t.lt.posted.between(date, dateRange)).count() |
---|
22 | | 22 | |
---|
23 | | 23 | |
---|
24 | def totalMinutes(self, channel, date, dateRange): | | def totalMinutes(self, channel, date, dateRange): |
---|
25 | query = self.t.lt.query.with_entities(func.sum(self.t.lt.duration).label('sum')).filter(self.t.lt.dcontext == "callback", self.t.lt.channel.like(channel+'%'), self.t.lt.calldate.between(date, dateRange)) | | query = self.t.lt.query.with_entities(func.sum(self.t.lt.duration).label('sum')).filter(self.t.lt.dcontext == "callback", self.t.lt.channel.like(channel+'%'), self.t.lt.calldate.between(date, dateRange)) |
---|
| | 24 | def totalMinutes(self, date, dateRange, channel=None): | | | 25 | query = self.t.lt.query.with_entities( |
---|
| | 26 | func.sum(self.t.lt.billsec).label('sum')).filter( |
---|
| | 27 | self.t.lt.dcontext == "callback", |
---|
| | 28 | self.t.lt.disposition == "ANSWERED", |
---|
| | 29 | self.t.lt.calldate.between(date, dateRange)) |
---|
| | 30 | |
---|
| | 31 | if channel is not None: |
---|
| | 32 | query = query.filter(self.t.lt.channel.like(channel+'%')) |
---|
| | 33 | |
---|
26 | sum = 0 | 34 | sum = 0 |
---|
27 | for res in query: | 35 | for res in query: |
---|
28 | if res.sum is not None: | 36 | if res.sum is not None: |
---|
… | | … | |
---|
39 | | 39 | |
---|
40 | | 40 | |
---|
41 | def average(self, date, dateRange): | 41 | def average(self, date, dateRange): |
---|
42 | query = self.t.lt.query.with_entities(func.avg(self.t.lt.duration).label('average')).filter(self.t.lt.dcontext == "callback", self.t.lt.calldate.between(date, dateRange)) | | query = self.t.lt.query.with_entities(func.avg(self.t.lt.duration).label('average')).filter(self.t.lt.dcontext == "callback", self.t.lt.calldate.between(date, dateRange)) |
---|
| | 42 | query = self.t.lt.query.with_entities( | | | 43 | func.avg(self.t.lt.billsec).label('average')).filter( |
---|
| | 44 | self.t.lt.dcontext == "callback", |
---|
| | 45 | self.t.lt.disposition == "ANSWERED", |
---|
| | 46 | self.t.lt.calldate.between(date, dateRange)) |
---|
| | 47 | |
---|
43 | average = 0 | 48 | average = 0 |
---|
44 | for res in query: | 49 | for res in query: |
---|
45 | if res.average is not None: | 50 | if res.average is not None: |
---|
46 | average = res.average/60 | 51 | average = res.average/60 |
---|
47 | return round(average, 4) | 52 | return round(average, 4) |
---|
48 | | 53 | |
---|
49 | def sum(self, date, dateRange): | | def sum(self, date, dateRange): |
---|
50 | query = self.t.lt.query.with_entities(func.sum(self.t.lt.duration).label('sum')).filter(self.t.lt.dcontext == "callback", self.t.lt.calldate.between(date, dateRange)) | | query = self.t.lt.query.with_entities(func.sum(self.t.lt.duration).label('sum')).filter(self.t.lt.dcontext == "callback", self.t.lt.calldate.between(date, dateRange)) |
---|
51 | sum = 0 | | sum = 0 |
---|
52 | for res in query: | | for res in query: |
---|
53 | if res.sum is not None: | | if res.sum is not None: |
---|
54 | sum = res.sum/60 | | sum = res.sum/60 |
---|
55 | return round(sum, 4) | | return round(sum, 4) |
---|
| | 54 | # def sum(self, date, dateRange): | | | 55 | # query = self.t.lt.query.with_entities( |
---|
| | 56 | # func.sum(self.t.lt.billsec).label('sum')).filter( |
---|
| | 57 | # self.t.lt.dcontext == "callback", |
---|
| | 58 | # self.t.lt.disposition == "ANSWERED", |
---|
| | 59 | # self.t.lt.calldate.between(date, dateRange)) |
---|
| | 60 | # sum = 0 |
---|
| | 61 | # for res in query: |
---|
| | 62 | # if res.sum is not None: |
---|
| | 63 | # sum = res.sum/60 |
---|
| | 64 | # return round(sum, 4) |
---|
56 | | 65 | |
---|
57 | | 66 | |
---|
58 | def missedCalls(self, date, dateRange, modem=None): | 67 | def missedCalls(self, date, dateRange, modem=None): |
---|
59 | if modem is None: | 68 | if modem is None: |
---|
60 | return self.t.lt.query.filter(((self.t.lt.dcontext == 'mobilink') | | 69 | return self.t.lt.query.filter(((self.t.lt.dcontext == 'mobilink') | |
---|
61 | (self.t.lt.dcontext == 'mobilinktata')) & | | (self.t.lt.dcontext == 'mobilinktata')) & |
---|
62 | (self.t.lt.calldate.between(date, dateRange))).count() | | (self.t.lt.calldate.between(date, dateRange))).count() |
---|
| | 70 | (self.t.lt.dcontext == | | | 71 | 'mobilinktata')) & |
---|
| | 72 | (self.t.lt.calldate.between(date, |
---|
| | 73 | dateRange))).count() |
---|
63 | else: | 74 | else: |
---|
64 | return self.t.lt.query.filter(self.t.lt.dcontext == modem, self.t.lt.calldate.between(date, dateRange)).count() | | return self.t.lt.query.filter(self.t.lt.dcontext == modem, self.t.lt.calldate.between(date, dateRange)).count() |
---|
| | 75 | return self.t.lt.query.filter(self.t.lt.dcontext == modem, | | | 76 | self.t.lt.calldate.between(date, |
---|
| | 77 | dateRange)).count() |
---|
65 | | 78 | |
---|
66 | | 79 | |
---|
| | 80 | def unAccountedCalls(self, date, dateRange): |
---|
| | 81 | return self.t.lt.query.filter(self.t.lt.dcontext == 'default', |
---|
| | 82 | self.t.lt.calldate.between(date, |
---|
| | 83 | dateRange)).count() |
---|
| | 84 | |
---|
| | 85 | |
---|
67 | def answeredCalls(self, date, dateRange): | 86 | def answeredCalls(self, date, dateRange): |
---|
68 | return self.t.lt.query.filter(self.t.lt.dcontext == 'callback', | 87 | return self.t.lt.query.filter(self.t.lt.dcontext == 'callback', |
---|
69 | self.t.lt.calldate.between(date, dateRange)).count() | | self.t.lt.calldate.between(date, dateRange)).count() |
---|
| | 88 | self.t.lt.disposition == 'ANSWERED', | | | 89 | self.t.lt.calldate.between(date, |
---|
| | 90 | dateRange)).count() |
---|
70 | | 91 | |
---|
71 | | 92 | |
---|
72 | def filter_calls_by_duration(self, date, dateRange, duration): | | def filter_calls_by_duration(self, date, dateRange, duration): |
---|
73 | return self.t.lt.query.filter(self.t.lt.dcontext == 'callback', self.t.lt.duration < duration, self.t.lt.calldate.between(date, dateRange)).count() | | return self.t.lt.query.filter(self.t.lt.dcontext == 'callback', self.t.lt.duration < duration, self.t.lt.calldate.between(date, dateRange)).count() |
---|
| | 93 | def filter_calls_by_duration(self, date, dateRange, billsec): | | | 94 | return self.t.lt.query.filter( |
---|
| | 95 | self.t.lt.dcontext == 'callback', self.t.lt.billsec < billsec, |
---|
| | 96 | self.t.lt.calldate.between(date, dateRange)).count() |
---|
74 | | 97 | |
---|
75 | | 98 | |
---|
76 | def call_distribution(self, date, dateRange, dcontext): | 99 | def call_distribution(self, date, dateRange, dcontext): |
---|
77 | startTimeStamp = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S') | 100 | startTimeStamp = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S') |
---|
78 | endTimeStamp = datetime.datetime.strptime(dateRange, '%Y-%m-%d %H:%M:%S') | 101 | endTimeStamp = datetime.datetime.strptime(dateRange, '%Y-%m-%d %H:%M:%S') |
---|
79 | result = self.t.lt.query.filter(self.t.lt.dcontext == dcontext, self.t.lt.calldate.between(date, dateRange)) | | result = self.t.lt.query.filter(self.t.lt.dcontext == dcontext, self.t.lt.calldate.between(date, dateRange)) |
---|
| | 102 | result = self.t.lt.query.filter( | | | 103 | self.t.lt.dcontext == dcontext, self.t.lt.calldate.between(date, dateRange)) |
---|
80 | slots = {} | 104 | slots = {} |
---|
81 | while(startTimeStamp - endTimeStamp <= datetime.timedelta(0)): | 105 | while(startTimeStamp - endTimeStamp <= datetime.timedelta(0)): |
---|
82 | date1 = startTimeStamp | 106 | date1 = startTimeStamp |
---|
83 | date2 = startTimeStamp + datetime.timedelta(seconds=3600) | 107 | date2 = startTimeStamp + datetime.timedelta(seconds=3600) |
---|
84 | startTimeStamp = date2 | 108 | startTimeStamp = date2 |
---|
85 | if slots.has_key('{0}-{1}'.format(date1.strftime('%H'), date2.strftime('%H'))): | 109 | if slots.has_key('{0}-{1}'.format(date1.strftime('%H'), date2.strftime('%H'))): |
---|
86 | slots['{0}-{1}'.format(date1.strftime('%H'), date2.strftime('%H'))] += result.filter(self.t.lt.calldate.between(date1, date2)).count() | | slots['{0}-{1}'.format(date1.strftime('%H'), date2.strftime('%H'))] += result.filter(self.t.lt.calldate.between(date1, date2)).count() |
---|
| | 110 | slots['{0}-{1}'.format(date1.strftime('%H'), | | | 111 | date2.strftime('%H'))] += result.filter( |
---|
| | 112 | self.t.lt.calldate.between(date1, date2)).count() |
---|
87 | else: | 113 | else: |
---|
88 | slots['{0}-{1}'.format(date1.strftime('%H'), date2.strftime('%H'))] = result.filter(self.t.lt.calldate.between(date1, date2)).count() | | slots['{0}-{1}'.format(date1.strftime('%H'), date2.strftime('%H'))] = result.filter(self.t.lt.calldate.between(date1, date2)).count() |
---|
| | 114 | slots['{0}-{1}'.format(date1.strftime('%H'), | | | 115 | date2.strftime('%H'))] = result.filter( |
---|
| | 116 | self.t.lt.calldate.between(date1, date2)).count() |
---|
89 | | 117 | |
---|
90 | maxLoad = max(slots, key = lambda x: slots.get(x) ) | 118 | maxLoad = max(slots, key = lambda x: slots.get(x) ) |
---|
91 | minLoad = [] | 119 | minLoad = [] |
---|
… | | … | |
---|
124 | | 124 | |
---|
125 | | 125 | |
---|
126 | def calls_unanswered(self, date, dateRange): | 126 | def calls_unanswered(self, date, dateRange): |
---|
127 | return self.t.lt.query.filter(self.t.lt.dcontext=='default', self.t.lt.calldate.between(date,dateRange)).count() | | return self.t.lt.query.filter(self.t.lt.dcontext=='default', self.t.lt.calldate.between(date,dateRange)).count() |
---|
| | 127 | return self.t.lt.query.filter(self.t.lt.disposition == 'NO ANSWER', | | | 128 | self.t.lt.dcontext == 'callback', |
---|
| | 129 | self.t.lt.calldate.between(date,dateRange)).count() |
---|
128 | | 130 | |
---|
129 | | 131 | |
---|
130 | def max_duration_UC(self, date, dateRange): | 132 | def max_duration_UC(self, date, dateRange): |
---|
131 | query = self.t.lt.query.with_entities(func.max(self.t.lt.duration).label('duration')).filter(self.t.lt.dcontext=='default', self.t.lt.calldate.between(date,dateRange)) | | query = self.t.lt.query.with_entities(func.max(self.t.lt.duration).label('duration')).filter(self.t.lt.dcontext=='default', self.t.lt.calldate.between(date,dateRange)) |
---|
| | 133 | query = self.t.lt.query.with_entities( | | | 134 | func.max(self.t.lt.duration).label('duration')).filter( |
---|
| | 135 | self.t.lt.dcontext=='default', self.t.lt.calldate.between(date,dateRange)) |
---|
132 | duration = 0 | 136 | duration = 0 |
---|
133 | for result in query: | 137 | for result in query: |
---|
134 | if result.duration is not None: | 138 | if result.duration is not None: |
---|
| | | | 25 | postings = query.Query('lb_postings') | 25 | postings = query.Query('lb_postings') |
---|
26 | callDetails = query.Query('cdr') | 26 | callDetails = query.Query('cdr') |
---|
27 | average_call_length = callDetails.average(startDate, endDate) | 27 | average_call_length = callDetails.average(startDate, endDate) |
---|
28 | audio_minutes = callDetails.sum(startDate, endDate) | | audio_minutes = callDetails.sum(startDate, endDate) |
---|
| | 28 | audio_minutes = callDetails.totalMinutes(startDate, endDate) | 29 | mobilink_load = callDetails.call_distribution(startDate, endDate, 'mobilink') | 29 | mobilink_load = callDetails.call_distribution(startDate, endDate, 'mobilink') |
---|
30 | mobilink_tata_load = callDetails.call_distribution(startDate, endDate, 'mobilinktata') | 30 | mobilink_tata_load = callDetails.call_distribution(startDate, endDate, 'mobilinktata') |
---|
31 | | 31 | |
---|
… | | … | |
---|
37 | """ | 37 | """ |
---|
38 | minutes = {} | 38 | minutes = {} |
---|
39 | for ip in conf.ip_addr: | 39 | for ip in conf.ip_addr: |
---|
40 | minutes[ip] = callDetails.totalMinutes(ip, startDate, endDate) | | minutes[ip] = callDetails.totalMinutes(ip, startDate, endDate) |
---|
| | 40 | minutes[ip] = callDetails.totalMinutes(startDate, endDate, ip) | 41 | return minutes | 41 | return minutes |
---|
42 | | 42 | |
---|
43 | def individual_load(): | 43 | def individual_load(): |
---|
… | | … | |
---|
98 | callDetails.calls_unanswered(startDate, endDate), | 98 | callDetails.calls_unanswered(startDate, endDate), |
---|
99 | | 99 | |
---|
100 | "Maximum_duration_of_unanswered_call": | 100 | "Maximum_duration_of_unanswered_call": |
---|
101 | callDetails.max_duration_UC(startDate, endDate) | | callDetails.max_duration_UC(startDate, endDate) |
---|
| | 101 | callDetails.max_duration_UC(startDate, endDate), | | | 102 | |
---|
| | 103 | "Number of calls failed permanently": callDetails.unAccountedCalls(startDate, endDate) |
---|
102 | }) | 104 | }) |
---|
103 | | 105 | |
---|
104 | def genReport(): | 106 | def genReport(): |
---|