Commit 41df78b3ffd3fdc6ac55bfbb4c685e9633ebd28b

  • avatar
  • arvind
  • Mon Mar 10 18:34:55 IST 2014
Code refactor and other improvements:
     Use the config file to import IP address of channels.
     Moving away from template based printing.  Generate a dict and
     print it as a template.
     Queries now return values rounded up to 4 decimal places.
query.py
(33 / 8)
  
11import logger
22from sqlalchemy.sql import func
33import datetime
4import decimal
45
6def 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
517class Query:
618 """Objects of query class can be used to run specific queries."""
719 def __init__(self, table):
2727 def recordings(self, date, dateRange):
2828 return self.t.lt.query.filter(self.t.lt.posted.between(date,
2929 dateRange)).count()
30
3031 def filter_by_title(self, title, date, dateRange):
3132 return self.t.lt.query.filter(self.t.lt.title.like(title+'%'),
3233 self.t.lt.posted.between(date, dateRange)).count()
3334
34 def load(self, channel, date, dateRange):
35
36 def totalMinutes(self, channel, date, dateRange):
3537 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))
3638 sum = 0
3739 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)
4043
44
4145 def average(self, date, dateRange):
4246 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))
4347 average = 0
4448 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)
4752
4853 def sum(self, date, dateRange):
4954 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))
5055 sum = 0
5156 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)
5460
61
5562 def missedCalls(self, date, dateRange, modem=None):
5663 if modem is None:
5764 return self.t.lt.query.filter(((self.t.lt.dcontext == 'mobilink') |
6767 else:
6868 return self.t.lt.query.filter(self.t.lt.dcontext == modem, self.t.lt.calldate.between(date, dateRange)).count()
6969
70
7071 def answeredCalls(self, date, dateRange):
7172 return self.t.lt.query.filter(self.t.lt.dcontext == 'callback',
7273 self.t.lt.calldate.between(date, dateRange)).count()
7374
75
7476 def filter_calls_by_duration(self, date, dateRange, duration):
7577 return self.t.lt.query.filter(self.t.lt.dcontext == 'callback', self.t.lt.duration < duration, self.t.lt.calldate.between(date, dateRange)).count()
7678
79
7780 def call_distribution(self, date, dateRange, dcontext):
7881 startTimeStamp = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S')
7982 endTimeStamp = datetime.datetime.strptime(dateRange, '%Y-%m-%d %H:%M:%S')
9898 minLoad.append(slot)
9999 return {"maxLoad": maxLoad, "maxCalls": slots[maxLoad], "minLoad": repr(minLoad)}
100100
101
101102 def calls_unanswered(self, date, dateRange):
102103 return self.t.lt.query.filter(self.t.lt.dcontext=='default', self.t.lt.calldate.between(date,dateRange)).count()
103104
105
104106 def max_duration_UC(self, date, dateRange):
105107 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))
106108 duration = 0
107109 for result in query:
108 duration = result.duration
110 if result.duration is not None:
111 duration = result.duration
109112 return duration
report.py
(62 / 32)
  
22import datetime
33import query
44import gmail
5import config as conf
56import mailConfig
6from string import Template
7import decimal
8
79parser = argparse.ArgumentParser(description="""Generate report for the date specified.
810 Start and end date default to present day.
911 Start time defaults to 00:00:00.
2626callDetails = query.Query('cdr')
2727average_call_length = callDetails.average(startDate, endDate)
2828audio_minutes = callDetails.sum(startDate, endDate)
29channel1_minutes = callDetails.load('SIP/10.0.0.30', startDate, endDate)
30channel2_minutes = callDetails.load('SIP/10.0.0.31', startDate, endDate)
31channel3_minutes = callDetails.load('SIP/10.0.0.33', startDate, endDate)
3229mobilink_load = callDetails.call_distribution(startDate, endDate, 'mobilink')
3330mobilink_tata_load = callDetails.call_distribution(startDate, endDate, 'mobilinktata')
3431
3532
36def genReport():
33def individual_audio_minutes():
34 """Return the total number of minutes on outgoing calls for every IP
35 address of modems specified in conf.py
3736
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
3942
40 recordings = '{0}: {1}'.format("Number of recordings made", postings.recordings(startDate, endDate))
43def 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
4149
42 impact_stories = '{0}: {1}'.format("Number of impact stories", postings.filter_by_title('impact', startDate, endDate))
50def genJSON():
51 return ({"Number_of_postings_published": postings.posts(startDate,
52 endDate),
4353
44 missed_calls = '{0}: {1}'.format("Number of missed calls", callDetails.missedCalls(startDate, endDate))
54 "Number_of_recordings_made": postings.recordings(startDate,
55 endDate),
4556
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),
4759
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),
4962
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'),
5165
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'),
5368
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),
5571
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),
5773
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,
5975
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),
6177
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(),
6379
64 ch1_load = '{0}: {1:.4f}'.format("Load on channel 10.0.0.20", channel1_minutes/audio_minutes)
80 "Load_on_channel": individual_load(),
6581
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"],
6783
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"],
6986
70 mobilink_max_load = '{0}: {1}'.format("Busiest hour for mobilink",mobilink_load["maxLoad"])
87 "Least_active_hour_for_mobilink": mobilink_load["minLoad"],
7188
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"],
7390
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"],
7593
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"],
7796
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),
7999
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 })
81103
82 unanswered_calls = '{0}: {1}'.format("Number of calls unanswered", callDetails.calls_unanswered(startDate, endDate))
104def genReport():
83105
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'
85114
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
89117
90118if args.mail is False:
91119 report = genReport()