Commit 41df78b3ffd3fdc6ac55bfbb4c685e9633ebd28b
- Diff rendering mode:
- inline
- side by side
query.py
(33 / 8)
  | |||
1 | 1 | import logger | |
2 | 2 | from sqlalchemy.sql import func | |
3 | 3 | import datetime | |
4 | import decimal | ||
4 | 5 | ||
6 | def toStr(fn): | ||
7 | def wrapped(*args, **kwargs): | ||
8 | response = fn(*args, **kwargs) | ||
9 | if type(response) is decimal.Decimal: | ||
10 | return str(response) | ||
11 | if type(response) is dict: | ||
12 | return repr(response) | ||
13 | else: | ||
14 | return str(response) | ||
15 | return wrapped | ||
16 | |||
5 | 17 | class Query: | |
6 | 18 | """Objects of query class can be used to run specific queries.""" | |
7 | 19 | def __init__(self, table): | |
… | … | ||
27 | 27 | def recordings(self, date, dateRange): | |
28 | 28 | return self.t.lt.query.filter(self.t.lt.posted.between(date, | |
29 | 29 | dateRange)).count() | |
30 | |||
30 | 31 | def filter_by_title(self, title, date, dateRange): | |
31 | 32 | return self.t.lt.query.filter(self.t.lt.title.like(title+'%'), | |
32 | 33 | self.t.lt.posted.between(date, dateRange)).count() | |
33 | 34 | ||
34 | def load(self, channel, date, dateRange): | ||
35 | |||
36 | def totalMinutes(self, channel, date, dateRange): | ||
35 | 37 | 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)) | |
36 | 38 | sum = 0 | |
37 | 39 | for res in query: | |
38 | sum = res.sum/60 | ||
39 | return sum | ||
40 | if res.sum is not None: | ||
41 | sum = res.sum/60 | ||
42 | return round(sum, 4) | ||
40 | 43 | ||
44 | |||
41 | 45 | def average(self, date, dateRange): | |
42 | 46 | 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)) | |
43 | 47 | average = 0 | |
44 | 48 | for res in query: | |
45 | average = res.average/60 | ||
46 | return average | ||
49 | if res.average is not None: | ||
50 | average = res.average/60 | ||
51 | return round(average, 4) | ||
47 | 52 | ||
48 | 53 | def sum(self, date, dateRange): | |
49 | 54 | 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)) | |
50 | 55 | sum = 0 | |
51 | 56 | for res in query: | |
52 | sum = res.sum/60 | ||
53 | return sum | ||
57 | if res.sum is not None: | ||
58 | sum = res.sum/60 | ||
59 | return round(sum, 4) | ||
54 | 60 | ||
61 | |||
55 | 62 | def missedCalls(self, date, dateRange, modem=None): | |
56 | 63 | if modem is None: | |
57 | 64 | return self.t.lt.query.filter(((self.t.lt.dcontext == 'mobilink') | | |
… | … | ||
67 | 67 | else: | |
68 | 68 | return self.t.lt.query.filter(self.t.lt.dcontext == modem, self.t.lt.calldate.between(date, dateRange)).count() | |
69 | 69 | ||
70 | |||
70 | 71 | def answeredCalls(self, date, dateRange): | |
71 | 72 | return self.t.lt.query.filter(self.t.lt.dcontext == 'callback', | |
72 | 73 | self.t.lt.calldate.between(date, dateRange)).count() | |
73 | 74 | ||
75 | |||
74 | 76 | def filter_calls_by_duration(self, date, dateRange, duration): | |
75 | 77 | return self.t.lt.query.filter(self.t.lt.dcontext == 'callback', self.t.lt.duration < duration, self.t.lt.calldate.between(date, dateRange)).count() | |
76 | 78 | ||
79 | |||
77 | 80 | def call_distribution(self, date, dateRange, dcontext): | |
78 | 81 | startTimeStamp = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S') | |
79 | 82 | endTimeStamp = datetime.datetime.strptime(dateRange, '%Y-%m-%d %H:%M:%S') | |
… | … | ||
98 | 98 | minLoad.append(slot) | |
99 | 99 | return {"maxLoad": maxLoad, "maxCalls": slots[maxLoad], "minLoad": repr(minLoad)} | |
100 | 100 | ||
101 | |||
101 | 102 | def calls_unanswered(self, date, dateRange): | |
102 | 103 | return self.t.lt.query.filter(self.t.lt.dcontext=='default', self.t.lt.calldate.between(date,dateRange)).count() | |
103 | 104 | ||
105 | |||
104 | 106 | def max_duration_UC(self, date, dateRange): | |
105 | 107 | 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)) | |
106 | 108 | duration = 0 | |
107 | 109 | for result in query: | |
108 | duration = result.duration | ||
110 | if result.duration is not None: | ||
111 | duration = result.duration | ||
109 | 112 | return duration |
report.py
(62 / 32)
  | |||
2 | 2 | import datetime | |
3 | 3 | import query | |
4 | 4 | import gmail | |
5 | import config as conf | ||
5 | 6 | import mailConfig | |
6 | from string import Template | ||
7 | import decimal | ||
8 | |||
7 | 9 | parser = argparse.ArgumentParser(description="""Generate report for the date specified. | |
8 | 10 | Start and end date default to present day. | |
9 | 11 | Start time defaults to 00:00:00. | |
… | … | ||
26 | 26 | callDetails = query.Query('cdr') | |
27 | 27 | average_call_length = callDetails.average(startDate, endDate) | |
28 | 28 | audio_minutes = callDetails.sum(startDate, endDate) | |
29 | channel1_minutes = callDetails.load('SIP/10.0.0.30', startDate, endDate) | ||
30 | channel2_minutes = callDetails.load('SIP/10.0.0.31', startDate, endDate) | ||
31 | channel3_minutes = callDetails.load('SIP/10.0.0.33', startDate, endDate) | ||
32 | 29 | mobilink_load = callDetails.call_distribution(startDate, endDate, 'mobilink') | |
33 | 30 | mobilink_tata_load = callDetails.call_distribution(startDate, endDate, 'mobilinktata') | |
34 | 31 | ||
35 | 32 | ||
36 | def genReport(): | ||
33 | def individual_audio_minutes(): | ||
34 | """Return the total number of minutes on outgoing calls for every IP | ||
35 | address of modems specified in conf.py | ||
37 | 36 | ||
38 | posts = '{0}: {1}'.format("Number of postings published", postings.posts(startDate, endDate)) | ||
37 | """ | ||
38 | minutes = {} | ||
39 | for ip in conf.ip_addr: | ||
40 | minutes[ip] = callDetails.totalMinutes(ip, startDate, endDate) | ||
41 | return minutes | ||
39 | 42 | ||
40 | recordings = '{0}: {1}'.format("Number of recordings made", postings.recordings(startDate, endDate)) | ||
43 | def individual_load(): | ||
44 | """ Return the fraction of load on each modem.""" | ||
45 | minutes = individual_audio_minutes() | ||
46 | for ip in minutes: | ||
47 | minutes[ip] = round(minutes[ip]/audio_minutes, 4) | ||
48 | return minutes | ||
41 | 49 | ||
42 | impact_stories = '{0}: {1}'.format("Number of impact stories", postings.filter_by_title('impact', startDate, endDate)) | ||
50 | def genJSON(): | ||
51 | return ({"Number_of_postings_published": postings.posts(startDate, | ||
52 | endDate), | ||
43 | 53 | ||
44 | missed_calls = '{0}: {1}'.format("Number of missed calls", callDetails.missedCalls(startDate, endDate)) | ||
54 | "Number_of_recordings_made": postings.recordings(startDate, | ||
55 | endDate), | ||
45 | 56 | ||
46 | missed_calls_mobilink = '{0}: {1}'.format("Number of missed calls on 'mobilink'", callDetails.missedCalls(startDate, endDate, 'mobilink')) | ||
57 | "Number_of_impact_stories": postings.filter_by_title('impact', | ||
58 | startDate, endDate), | ||
47 | 59 | ||
48 | missed_calls_mobilink_tata = '{0}: {1}'.format("Number of missed calls on 'mobilinktata'", callDetails.missedCalls(startDate, endDate,'mobilinktata')) | ||
60 | "Number_of_missed_calls": callDetails.missedCalls(startDate, | ||
61 | endDate), | ||
49 | 62 | ||
50 | answered_calls = '{0}: {1}'.format("Number of calls answered", callDetails.answeredCalls(startDate, endDate)) | ||
63 | "Number_of_missed_calls_on_mobilink": | ||
64 | callDetails.missedCalls(startDate, endDate, 'mobilink'), | ||
51 | 65 | ||
52 | filtered_calls = '{0}: {1}'.format("Number of calls lasting less than 30 seconds", callDetails.filter_calls_by_duration(startDate, endDate, 30)) | ||
66 | "Number_of_missed_calls_on_mobilinktata": | ||
67 | callDetails.missedCalls(startDate, endDate,'mobilinktata'), | ||
53 | 68 | ||
54 | average_Call_Length = '{0}: {1:.4f}'.format("Average length of calls", average_call_length) | ||
69 | "Number_of_calls_answered": callDetails.answeredCalls(startDate, | ||
70 | endDate), | ||
55 | 71 | ||
56 | audio_Minutes = '{0}: {1:.4f}'.format("Total number of audio minutes played", audio_minutes) | ||
72 | "Number_of_calls_lasting_less_than_30_seconds": callDetails.filter_calls_by_duration(startDate, endDate, 30), | ||
57 | 73 | ||
58 | ch1_minutes = '{0}: {1:.4f}'.format("Audio minutes on channel 10.0.0.20", channel1_minutes) | ||
74 | "Average_length_of_calls": average_call_length, | ||
59 | 75 | ||
60 | ch2_minutes = '{0}: {1:.4f}'.format("Audio minutes on channel 10.0.0.21", channel2_minutes) | ||
76 | "Total_number_of_audio_minutes_played": str(audio_minutes), | ||
61 | 77 | ||
62 | ch3_minutes = '{0}: {1:.4f}'.format("Audio minutes on channel 10.0.0.22", channel3_minutes) | ||
78 | "Audio_minutes_on_channel": individual_audio_minutes(), | ||
63 | 79 | ||
64 | ch1_load = '{0}: {1:.4f}'.format("Load on channel 10.0.0.20", channel1_minutes/audio_minutes) | ||
80 | "Load_on_channel": individual_load(), | ||
65 | 81 | ||
66 | ch2_load = '{0}: {1:.4f}'.format("Load on channel 10.0.0.21", channel2_minutes/audio_minutes) | ||
82 | "Busiest_hour_for_mobilink": mobilink_load["maxLoad"], | ||
67 | 83 | ||
68 | ch3_load = '{0}: {1:.4f}'.format("Load on channel 10.0.0.22", channel3_minutes/audio_minutes) | ||
84 | "Number_of_calls_in_busiest_hour_for_mobilink": | ||
85 | mobilink_load["maxCalls"], | ||
69 | 86 | ||
70 | mobilink_max_load = '{0}: {1}'.format("Busiest hour for mobilink",mobilink_load["maxLoad"]) | ||
87 | "Least_active_hour_for_mobilink": mobilink_load["minLoad"], | ||
71 | 88 | ||
72 | mobilink_max_calls = '{0}: {1}'.format("Number of calls in busiest hour for mobilink",mobilink_load["maxCalls"]) | ||
89 | "Busiest_hour_for_mobilinktata": mobilink_tata_load["maxLoad"], | ||
73 | 90 | ||
74 | mobilink_min_load = '{0}: {1}'.format("Least active hour for mobilink",mobilink_load["minLoad"]) | ||
91 | "Number_of_calls_in_busiest_hour_for_mobilinktata": | ||
92 | mobilink_tata_load["maxCalls"], | ||
75 | 93 | ||
76 | mobilink_tata_max_load = '{0}: {1}'.format("Busiest hour for mobilinktata",mobilink_tata_load["maxLoad"]) | ||
94 | "Least_active_hour_for_mobilinktata": | ||
95 | mobilink_tata_load["minLoad"], | ||
77 | 96 | ||
78 | mobilink_tata_max_calls = '{0}: {1}'.format("Number of calls in busiest hour for mobilinktata",mobilink_tata_load["maxCalls"]) | ||
97 | "Number_of_calls_unanswered": | ||
98 | callDetails.calls_unanswered(startDate, endDate), | ||
79 | 99 | ||
80 | mobilink_tata_min_load = '{0}: {1}'.format("Least active hour for mobilinktata",mobilink_tata_load["minLoad"]) | ||
100 | "Maximum_duration_of_unanswered_call": | ||
101 | callDetails.max_duration_UC(startDate, endDate) | ||
102 | }) | ||
81 | 103 | ||
82 | unanswered_calls = '{0}: {1}'.format("Number of calls unanswered", callDetails.calls_unanswered(startDate, endDate)) | ||
104 | def genReport(): | ||
83 | 105 | ||
84 | max_duration_UC = '{0}: {1}'.format("Maximum duration of unanswered call(in seconds)", callDetails.max_duration_UC(startDate, endDate)) | ||
106 | rep = genJSON() | ||
107 | keys = rep.keys() | ||
108 | template = '' | ||
109 | for key in keys: | ||
110 | if type(rep[key]) is dict: | ||
111 | for item in rep[key]: | ||
112 | rep[key][item] = str(rep[key][item]) | ||
113 | template+= key.replace('_', ' ') + ': ' + str(rep[key]) + '\n' | ||
85 | 114 | ||
86 | t =Template('$posts\n$recordings\n$impact_stories\n$missed_calls\n$missed_calls_mobilink\n$missed_calls_mobilink_tata\n$answered_calls\n$unanswered_calls\n$max_duration_uc\n$filtered_calls\n$average_call_length\n$audio_minutes\n$ch1_minutes\n$ch2_minutes\n$ch3_minutes\n$ch1_load\n$ch2_load\n$ch3_load\n$mobilink_max_load\n$mobilink_max_calls\n$mobilink_min_load\n$mobilink_tata_max_load\n$mobilink_tata_max_calls\n$mobilink_tata_min_load') | ||
87 | report = t.substitute(posts=posts,recordings=recordings,impact_stories=impact_stories,missed_calls=missed_calls,missed_calls_mobilink=missed_calls_mobilink,missed_calls_mobilink_tata=missed_calls_mobilink_tata,answered_calls=answered_calls,unanswered_calls=unanswered_calls,max_duration_uc=max_duration_UC,filtered_calls=filtered_calls,average_call_length=average_Call_Length,audio_minutes=audio_Minutes,ch1_minutes=ch1_minutes,ch2_minutes=ch2_minutes,ch3_minutes=ch3_minutes,ch1_load=ch1_load,ch2_load=ch2_load,ch3_load=ch3_load,mobilink_max_load=mobilink_max_load,mobilink_max_calls=mobilink_max_calls,mobilink_min_load=mobilink_min_load,mobilink_tata_max_load=mobilink_tata_max_load,mobilink_tata_max_calls=mobilink_tata_max_calls,mobilink_tata_min_load=mobilink_tata_min_load) | ||
88 | return report | ||
115 | return template | ||
116 | |||
89 | 117 | ||
90 | 118 | if args.mail is False: | |
91 | 119 | report = genReport() |