1
|
|
|
# Copyright 2013 Mathias WOLFF |
2
|
|
|
# This file is part of pyfreebilling. |
3
|
|
|
# |
4
|
|
|
# pyfreebilling is free software: you can redistribute it and/or modify |
5
|
|
|
# it under the terms of the GNU General Public License as published by |
6
|
|
|
# the Free Software Foundation, either version 3 of the License, or |
7
|
|
|
# (at your option) any later version. |
8
|
|
|
# |
9
|
|
|
# pyfreebilling is distributed in the hope that it will be useful, |
10
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
11
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12
|
|
|
# GNU General Public License for more details. |
13
|
|
|
# |
14
|
|
|
# You should have received a copy of the GNU General Public License |
15
|
|
|
# along with pyfreebilling. If not, see <http://www.gnu.org/licenses/> |
16
|
|
|
|
17
|
|
|
from django.shortcuts import render |
18
|
|
|
from django.template import RequestContext, Context, loader |
19
|
|
|
from django.http import HttpResponseRedirect, HttpResponse |
20
|
|
|
from django.conf import settings |
21
|
|
|
from django.contrib.admin.views.decorators import staff_member_required |
22
|
|
|
from django.db.models import Sum, Avg, Count, Max, Min |
23
|
|
|
from django.views.decorators.cache import cache_page |
24
|
|
|
from django.views.generic import TemplateView |
25
|
|
|
from django.utils import timezone |
26
|
|
|
from django.contrib import messages |
27
|
|
|
from django.contrib.auth.decorators import user_passes_test |
28
|
|
|
from django.utils.translation import ugettext_lazy as _ |
29
|
|
|
|
30
|
|
|
from django_tables2 import RequestConfig |
31
|
|
|
|
32
|
|
|
from .utils import time_series |
33
|
|
|
import time |
34
|
|
|
import datetime |
35
|
|
|
import qsstats |
36
|
|
|
import json |
37
|
|
|
import pytz |
38
|
|
|
import markdown |
39
|
|
|
|
40
|
|
|
try: |
41
|
|
|
# python 2 |
42
|
|
|
from urllib2 import urlopen |
43
|
|
|
except ImportError: |
44
|
|
|
# python 3 |
45
|
|
|
from urllib.request import urlopen |
46
|
|
|
|
47
|
|
|
# from pyfreebilling.switch import esl |
48
|
|
|
|
49
|
|
|
from pyfreebilling import __version__ |
50
|
|
|
|
51
|
|
|
from pyfreebilling.cdr.models import CDR |
52
|
|
|
|
53
|
|
|
from pyfreebilling.customerdirectory.models import CustomerDirectory |
54
|
|
|
|
55
|
|
|
from .utils import round_value, getvar, return_query_string |
56
|
|
|
from .forms import CDRSearchForm |
57
|
|
|
from .models import DimCustomerDestination, DimProviderDestination, DimCustomerHangupcause, Company, SipProfile |
58
|
|
|
from .tables import TopCustTable, TopProvTable, TopDestCustTable, TopDestProvTable |
59
|
|
|
|
60
|
|
|
|
61
|
|
|
@staff_member_required |
62
|
|
|
@cache_page(60*60*24) |
63
|
|
|
def license_view(request): |
64
|
|
|
url = "https://www.gnu.org/licenses/agpl-3.0.md" |
65
|
|
|
str = urlopen(url).read() |
66
|
|
|
license = markdown.markdown(str) |
67
|
|
|
context = {'license': license} |
68
|
|
|
return render(request, 'admin/license.html', context) |
69
|
|
|
|
70
|
|
|
|
71
|
|
|
@staff_member_required |
72
|
|
|
def global_stats_view(request, vue): |
73
|
|
|
# set start_date and end_date |
74
|
|
|
# default yesterday stats |
75
|
|
|
if vue == 'customer' or vue == 'dest_customer': |
76
|
|
|
qs = DimCustomerDestination.objects.all() |
77
|
|
|
if vue == 'provider' or vue == 'dest_provider': |
78
|
|
|
qs = DimProviderDestination.objects.all() |
79
|
|
|
|
80
|
|
|
current_tz = pytz.utc |
81
|
|
|
dt = datetime.datetime.now() |
82
|
|
|
end_date = datetime.date(dt.year, dt.month, dt.day) |
83
|
|
|
# end_date = datetime.date(2014, 8, 28) |
84
|
|
|
start_date = end_date - datetime.timedelta(days=1) |
85
|
|
|
qs_orderby = '-total_sell' |
86
|
|
|
|
87
|
|
|
# Get the q GET parameter |
88
|
|
|
# date from and to and check value |
89
|
|
|
start_d = {'y': [], 'm': [], 'd': [], 'status': True} |
90
|
|
|
end_d = {'y': [], 'm': [], 'min': [], 'status': True} |
91
|
|
|
li = ['y', 'm', 'd'] |
92
|
|
|
for i in li: |
93
|
|
|
start_d[str(i)] = request.GET.get("from_" + str(i)) |
94
|
|
|
if start_d[str(i)] and start_d[str(i)].isnumeric(): |
95
|
|
|
start_d[str(i)] = int(start_d[str(i)]) |
96
|
|
|
else: |
97
|
|
|
start_d['status'] = False |
98
|
|
|
end_d[str(i)] = request.GET.get("to_" + str(i)) |
99
|
|
|
if end_d[str(i)] and end_d[str(i)].isnumeric(): |
100
|
|
|
end_d[str(i)] = int(end_d[str(i)]) |
101
|
|
|
else: |
102
|
|
|
end_d['status'] = False |
103
|
|
|
# dest num |
104
|
|
|
dest_num = request.GET.get("dest_num") |
105
|
|
|
company = request.GET.get("company") |
106
|
|
|
if start_d['status']: |
107
|
|
|
start_date = datetime.datetime( |
108
|
|
|
start_d['y'], start_d['m'], start_d['d'], 00, 00) |
109
|
|
|
if end_d['status']: |
110
|
|
|
end_date = datetime.datetime( |
111
|
|
|
end_d['y'], end_d['m'], end_d['d'], 00, 00) |
112
|
|
|
if start_date and end_date: |
113
|
|
|
qs = qs.filter(date__date__range=(start_date, end_date)) |
114
|
|
|
|
115
|
|
|
if dest_num: |
116
|
|
|
qs = qs.filter(destination__startswith=dest_num) |
117
|
|
|
|
118
|
|
|
if company: |
119
|
|
|
if vue == 'customer' or vue == 'dest_customer': |
120
|
|
|
qs = qs.filter(customer__name__contains=company) |
121
|
|
|
if vue == 'provider' or vue == 'dest_provider': |
122
|
|
|
qs = qs.filter(provider__name__contains=company) |
123
|
|
|
|
124
|
|
|
if vue == 'customer': |
125
|
|
|
qs1 = qs.values('customer__name', 'customer__cb_currency__code') |
126
|
|
|
if vue == 'dest_customer' or vue == 'dest_provider': |
127
|
|
|
qs1 = qs.values('destination') |
128
|
|
|
if vue == 'provider': |
129
|
|
|
qs1 = qs.values('provider__name', 'provider__cb_currency__code') |
130
|
|
|
stats_table = qs1.\ |
131
|
|
|
annotate(total_sell=Sum('total_sell')).\ |
132
|
|
|
annotate(success_calls=Sum('success_calls')).\ |
133
|
|
|
annotate(total_calls=Sum('total_calls')).\ |
134
|
|
|
annotate(total_cost=Sum('total_cost')).\ |
135
|
|
|
annotate(total_duration=Sum('total_duration')).\ |
136
|
|
|
annotate(max_duration=Max('max_duration')).\ |
137
|
|
|
annotate(min_duration=Min('min_duration')).\ |
138
|
|
|
annotate(avg_duration=Min('avg_duration')).\ |
139
|
|
|
order_by('-total_sell') |
140
|
|
|
total_table = qs.\ |
141
|
|
|
aggregate(total_sell=Sum('total_sell'), |
142
|
|
|
success_calls=Sum('success_calls'),\ |
143
|
|
|
total_calls=Sum('total_calls'),\ |
144
|
|
|
total_cost=Sum('total_cost'),\ |
145
|
|
|
total_duration=Sum('total_duration'),\ |
146
|
|
|
max_duration=Max('max_duration'),\ |
147
|
|
|
min_duration=Min('min_duration'),\ |
148
|
|
|
avg_duration=Min('avg_duration')) |
149
|
|
|
|
150
|
|
|
if vue == 'customer': |
151
|
|
|
table = TopCustTable(stats_table) |
152
|
|
|
if vue == 'dest_customer': |
153
|
|
|
table = TopDestCustTable(stats_table) |
154
|
|
|
if vue == 'provider': |
155
|
|
|
table = TopProvTable(stats_table) |
156
|
|
|
if vue == 'dest_provider': |
157
|
|
|
table = TopDestProvTable(stats_table) |
158
|
|
|
RequestConfig(request, paginate={"per_page": 100}).configure(table) |
159
|
|
|
#import pdb; pdb.set_trace() |
160
|
|
|
return render(request, 'admin/customers_stats.html', locals()) |
161
|
|
|
|
162
|
|
|
|
163
|
|
|
@staff_member_required |
164
|
|
|
def customers_stats_view(request): |
165
|
|
|
return global_stats_view(request, vue='customer') |
166
|
|
|
|
167
|
|
|
|
168
|
|
|
@staff_member_required |
169
|
|
|
def destination_customers_stats_view(request): |
170
|
|
|
return global_stats_view(request, vue='dest_customer') |
171
|
|
|
|
172
|
|
|
|
173
|
|
|
@staff_member_required |
174
|
|
|
def providers_stats_view(request): |
175
|
|
|
return global_stats_view(request, vue='provider') |
176
|
|
|
|
177
|
|
|
|
178
|
|
|
@staff_member_required |
179
|
|
|
def destination_providers_stats_view(request): |
180
|
|
|
return global_stats_view(request, vue='dest_provider') |
181
|
|
|
|
182
|
|
|
|
183
|
|
|
# @staff_member_required |
184
|
|
|
# def FsDirectoryUpdateView(request): |
185
|
|
|
# messages.info(request, """Reloading FS""") |
186
|
|
|
# try: |
187
|
|
|
# t = loader.get_template('xml/directory.conf.xml') |
188
|
|
|
# except IOError: |
189
|
|
|
# messages.error(request, """customer sip config xml file update failed. |
190
|
|
|
# Can not load template file !""") |
191
|
|
|
# customerdirectorys = CustomerDirectory.objects.filter( |
192
|
|
|
# company__customer_enabled__exact=True, enabled=True) |
193
|
|
|
# accounts = Company.objects.filter(customer_enabled=True) |
194
|
|
|
# c = Context({"customerdirectorys": customerdirectorys, |
195
|
|
|
# "accounts": accounts}) |
196
|
|
|
# try: |
197
|
|
|
# f = open('/usr/local/freeswitch/conf/directory/default.xml', 'w') |
198
|
|
|
# try: |
199
|
|
|
# f.write(t.render(c)) |
200
|
|
|
# f.close() |
201
|
|
|
# try: |
202
|
|
|
# fs = esl.getReloadACL() |
203
|
|
|
# messages.success(request, "FS successfully reload") |
204
|
|
|
# except IOError: |
205
|
|
|
# messages.error(request, """customer sip config xml file update |
206
|
|
|
# failed. FS ACL update failed ! Try manually - %s""" % fs) |
207
|
|
|
# finally: |
208
|
|
|
# # f.close() |
209
|
|
|
# messages.success(request, """customer sip config xml file update |
210
|
|
|
# success""") |
211
|
|
|
# except IOError: |
212
|
|
|
# messages.error(request, """customer sip config xml file update failed. |
213
|
|
|
# Can not create file !""") |
214
|
|
|
# pfb_version = __version__ |
215
|
|
|
# return render_to_response('admin/admin_status.html', locals(), |
216
|
|
|
# context_instance=RequestContext(request)) |
217
|
|
|
|
218
|
|
|
|
219
|
|
|
# def FsSofiaUpdateView(request): |
220
|
|
|
# """ generate new sofia xml config file """ |
221
|
|
|
# try: |
222
|
|
|
# t = loader.get_template('xml/sofia.conf.xml') |
223
|
|
|
# except IOError: |
224
|
|
|
# messages.error(request, |
225
|
|
|
# """sofia config xml file update failed. Can not load |
226
|
|
|
# template file !""") |
227
|
|
|
# sipprofiles = SipProfile.objects.all() |
228
|
|
|
# accounts = Company.objects.filter(supplier_enabled=True) |
229
|
|
|
# c = Context({"sipprofiles": sipprofiles, "accounts": accounts}) |
230
|
|
|
# try: |
231
|
|
|
# f = open('/usr/local/freeswitch/conf/autoload_configs/sofia.conf.xml', |
232
|
|
|
# 'w') |
233
|
|
|
# try: |
234
|
|
|
# f.write(t.render(c)) |
235
|
|
|
# f.close() |
236
|
|
|
# try: |
237
|
|
|
# fs = esl.getReloadGateway(request) |
238
|
|
|
# messages.success(request, "FS successfully reload") |
239
|
|
|
# except IOError: |
240
|
|
|
# messages.error(request, """customer sip config xml file update |
241
|
|
|
# failed. FS ACL update failed ! Try manually -- %s""" % fs) |
242
|
|
|
# finally: |
243
|
|
|
# # f.close() |
244
|
|
|
# messages.success(request, "sofia config xml file update success") |
245
|
|
|
# except IOError: |
246
|
|
|
# messages.error(request, """sofia config xml file update failed. Can |
247
|
|
|
# not create file !""") |
248
|
|
|
# pfb_version = __version__ |
249
|
|
|
# return render_to_response('admin/admin_status.html', locals(), |
250
|
|
|
# context_instance=RequestContext(request)) |
251
|
|
|
|
252
|
|
|
|
253
|
|
|
@staff_member_required |
254
|
|
|
def admin_status_view(request): |
255
|
|
|
# print status page |
256
|
|
|
# pfb_version = settings.PFB_VERSION |
257
|
|
|
pfb_version = __version__ |
258
|
|
|
return render(request, 'admin/admin_status.html', locals()) |
259
|
|
|
|
260
|
|
|
|
261
|
|
|
@staff_member_required |
262
|
|
|
def admin_listmodels_view(request): |
263
|
|
|
# print status page |
264
|
|
|
# pfb_version = settings.PFB_VERSION |
265
|
|
|
|
266
|
|
|
return render_to_response('admin/list_models.html', locals(), |
267
|
|
|
context_instance=RequestContext(request)) |
268
|
|
|
|
269
|
|
|
|
270
|
|
|
def _margin_series(sell_series, cost_series): |
271
|
|
|
""" |
272
|
|
|
Substraction between sell time series to cost time series |
273
|
|
|
""" |
274
|
|
|
sum = 0 |
275
|
|
|
l = [] |
276
|
|
|
for ((d, sell), (_, cost)) in zip(sell_series, cost_series): |
277
|
|
|
if sell and cost: |
278
|
|
|
sum += (sell - cost) |
279
|
|
|
else: |
280
|
|
|
sum += 0 |
281
|
|
|
l.append((d, sum)) |
282
|
|
|
return l |
283
|
|
|
|
284
|
|
|
|
285
|
|
|
@user_passes_test(lambda u: u.is_superuser) |
286
|
|
|
@staff_member_required |
287
|
|
|
def live_report_view(request): |
288
|
|
|
""" selecting cdr and live stats calculated from selection """ |
289
|
|
|
|
290
|
|
|
form = CDRSearchForm(request.user, request.POST or None) |
291
|
|
|
|
292
|
|
|
if request.method == 'POST': |
293
|
|
|
|
294
|
|
|
if form.is_valid(): |
295
|
|
|
query_string = '' |
296
|
|
|
query_answer = '' |
297
|
|
|
|
298
|
|
|
tzname = settings.TIME_ZONE |
299
|
|
|
offset = datetime.datetime.now( |
300
|
|
|
pytz.timezone(tzname)).strftime('%z') |
301
|
|
|
|
302
|
|
|
from_date = getvar(request, 'from_date_0') |
303
|
|
|
if from_date: |
304
|
|
|
formated_date = from_date[0:4] + '-' + from_date[8:10] + '-' + from_date[ |
305
|
|
|
5:7] + '+' + from_date[11:13] + '%3A' + from_date[14:16] + '%3A00' |
306
|
|
|
if offset[0] == '+': |
307
|
|
|
formated_date = formated_date + '%2B' |
308
|
|
|
else: |
309
|
|
|
formated_date = formated_date + '%2D' |
310
|
|
|
formated_date = formated_date + \ |
311
|
|
|
offset[1:3] + '%3A' + offset[3:5] |
312
|
|
|
date_string = 'start_stamp__gte=' + str(formated_date) |
313
|
|
|
query_string = return_query_string(query_string, date_string) |
314
|
|
|
#import pdb; pdb.set_trace() |
315
|
|
|
|
316
|
|
|
to_date = getvar(request, 'to_date_0') |
317
|
|
|
if to_date: |
318
|
|
|
formated_date = to_date[0:4] + '-' + to_date[8:10] + '-' + to_date[ |
319
|
|
|
5:7] + '+' + to_date[11:13] + '%3A' + to_date[14:16] + '%3A00' |
320
|
|
|
if offset[0] == '+': |
321
|
|
|
formated_date = formated_date + '%2B' |
322
|
|
|
else: |
323
|
|
|
formated_date = formated_date + '%2D' |
324
|
|
|
formated_date = formated_date + \ |
325
|
|
|
offset[1:3] + '%3A' + offset[3:5] |
326
|
|
|
date_string = 'start_stamp__lt=' + str(formated_date) |
327
|
|
|
query_string = return_query_string(query_string, date_string) |
328
|
|
|
|
329
|
|
|
customer_id = getvar(request, 'customer_id') |
330
|
|
|
if customer_id and customer_id != '0': |
331
|
|
|
customer_string = 'customer__id__exact=' + str(customer_id) |
332
|
|
|
query_string = return_query_string( |
333
|
|
|
query_string, customer_string) |
334
|
|
|
|
335
|
|
|
provider_id = getvar(request, 'provider_id') |
336
|
|
|
if provider_id and provider_id != '0': |
337
|
|
|
provider_string = 'lcr_carrier_id__id__exact=' + \ |
338
|
|
|
str(provider_id) |
339
|
|
|
query_string = return_query_string( |
340
|
|
|
query_string, provider_string) |
341
|
|
|
|
342
|
|
|
ratecard_id = getvar(request, 'ratecard_id') |
343
|
|
|
if ratecard_id and ratecard_id != '0': |
344
|
|
|
ratecard_string = 'ratecard_id__id__exact=' + str(ratecard_id) |
345
|
|
|
query_string = return_query_string( |
346
|
|
|
query_string, ratecard_string) |
347
|
|
|
|
348
|
|
|
lcr_id = getvar(request, 'lcr_id') |
349
|
|
|
if lcr_id and lcr_id != '0': |
350
|
|
|
lcr_string = 'lcr_group_id__id__exact=' + str(lcr_id) |
351
|
|
|
query_string = return_query_string(query_string, lcr_string) |
352
|
|
|
|
353
|
|
|
dest_num = getvar(request, 'dest_num') |
354
|
|
|
if dest_num: |
355
|
|
|
dstnum_string = 'destination_number__startswith=' + \ |
356
|
|
|
str(dest_num) |
357
|
|
|
query_string = return_query_string(query_string, dstnum_string) |
358
|
|
|
|
359
|
|
|
if query_string: |
360
|
|
|
query_answer = '/extranet/cdr/cdr/?' + str(query_string) |
361
|
|
|
else: |
362
|
|
|
query_answer = '/extranet/cdr/cdr/' |
363
|
|
|
|
364
|
|
|
return HttpResponseRedirect(query_answer) |
365
|
|
|
else: |
366
|
|
|
form = CDRSearchForm(request.user) |
367
|
|
|
|
368
|
|
|
request.session['msg'] = '' |
369
|
|
|
request.session['error_msg'] = '' |
370
|
|
|
|
371
|
|
|
return render(request, 'admin/live_report.html', locals()) |
372
|
|
|
|
373
|
|
|
|
374
|
|
|
class ChartData(object): |
375
|
|
|
|
376
|
|
|
@classmethod |
377
|
|
|
def get_stats_revenue(cls): |
378
|
|
|
data = [] |
379
|
|
|
data1 = {'key': [], 'values': [], 'color': '#2ca02c'} |
380
|
|
|
data2 = {'key': [], 'values': []} |
381
|
|
|
data3 = {'key': [], 'area': 'true', 'values': [], 'color': '#ff7f0e'} |
382
|
|
|
data4 = {'key': [], 'area': 'true', 'values': [], 'color': '#7777ff'} |
383
|
|
|
|
384
|
|
|
values_sell = [] |
385
|
|
|
values_cost = [] |
386
|
|
|
values_duration = [] |
387
|
|
|
margin = [] |
388
|
|
|
values_margin = [] |
389
|
|
|
|
390
|
|
|
qs = CDR.objects.filter(effective_duration__gt="0") |
391
|
|
|
qs_d = DimCustomerDestination.objects.all() |
392
|
|
|
# qs_h = DimCustomerHangupcause.objects.all() |
393
|
|
|
qss_sell = qsstats.QuerySetStats(qs, 'start_stamp', |
394
|
|
|
aggregate=Sum('total_sell')) |
395
|
|
|
qss_cost = qsstats.QuerySetStats(qs, 'start_stamp', |
396
|
|
|
aggregate=Sum('total_cost')) |
397
|
|
|
qss_sum_duration = qsstats.QuerySetStats(qs, 'start_stamp', |
398
|
|
|
aggregate=Sum('effective_duration')) |
399
|
|
|
today = datetime.date.today() - datetime.timedelta(days=0) |
400
|
|
|
firstday = today - datetime.timedelta(days=90) |
401
|
|
|
# stats_sell = qss_sell.time_series(seven_days_ago, today) |
402
|
|
|
# stats_cost = qss_sell.time_series(seven_days_ago, today) |
403
|
|
|
# stats_duration = qss_sum_duration.time_series(seven_days_ago, today) |
404
|
|
|
|
405
|
|
|
ts_total_calls = time_series( |
406
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_calls')) |
407
|
|
|
ts_success_calls = time_series( |
408
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('success_calls')) |
409
|
|
|
stats_duration = time_series( |
410
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_duration')) |
411
|
|
|
stats_sell = time_series( |
412
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_sell')) |
413
|
|
|
stats_cost = time_series( |
414
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_cost')) |
415
|
|
|
|
416
|
|
|
for i in range(len(stats_sell)): |
417
|
|
|
values_sell.append( |
418
|
|
|
[int(time.mktime(stats_sell[i][0].timetuple()) * 1000), |
419
|
|
|
round_value(stats_sell[i][1])]) |
420
|
|
|
|
421
|
|
|
data1['key'].append("Revenue") |
422
|
|
|
data1['values'] = values_sell |
423
|
|
|
data.append(data1) |
424
|
|
|
|
425
|
|
|
for i in range(len(stats_sell)): |
426
|
|
|
temp_data = [ |
427
|
|
|
int(time.mktime(stats_sell[i][0].timetuple()) * 1000), |
428
|
|
|
# round_value(stats_sell[i][1]) |
429
|
|
|
# round_value(stats_cost[i][1]), |
430
|
|
|
int(round_value(stats_duration[i][1])) |
431
|
|
|
] |
432
|
|
|
values_duration.append(temp_data) |
433
|
|
|
|
434
|
|
|
data2['values'] = values_duration |
435
|
|
|
# data2['bar'].append('true') |
436
|
|
|
data2['key'].append("Duration") |
437
|
|
|
# data.append(data2) |
438
|
|
|
|
439
|
|
|
for i in range(len(stats_sell)): |
440
|
|
|
values_cost.append( |
441
|
|
|
[int(time.mktime(stats_cost[i][0].timetuple()) * 1000), |
442
|
|
|
round_value(stats_cost[i][1])]) |
443
|
|
|
|
444
|
|
|
data3['key'].append("Cost") |
445
|
|
|
data3['values'] = values_cost |
446
|
|
|
data.append(data3) |
447
|
|
|
|
448
|
|
|
for i in range(len(stats_sell)): |
449
|
|
|
if stats_sell[i][1]: |
450
|
|
|
if stats_cost[i][1]: |
451
|
|
|
margin.append(stats_sell[i][1] - stats_cost[i][1]) |
452
|
|
|
else: |
453
|
|
|
margin.append(stats_sell[i][1]) |
454
|
|
|
else: |
455
|
|
|
if stats_cost[i][1]: |
456
|
|
|
margin.append(0 - stats_cost[i][1]) |
457
|
|
|
else: |
458
|
|
|
margin.append(0) |
459
|
|
|
values_margin.append( |
460
|
|
|
[int(time.mktime(stats_cost[i][0].timetuple()) * 1000), |
461
|
|
|
round_value(margin[i])]) |
462
|
|
|
|
463
|
|
|
data4['key'].append("Margin") |
464
|
|
|
data4['values'] = values_margin |
465
|
|
|
data.append(data4) |
466
|
|
|
|
467
|
|
|
#data = [{"values": [[1400281200000, 3.36], [1400367600000, 0.03], [1400454000000, 30.15], [1400540400000, 34.57], [1400626800000, 30.73], [1400713200000, 32.12], [1400799600000, 60.69], [1400886000000, 3.61], [1400972400000, 0.05], [1401058800000, 68.54], [1401145200000, 339.0], [1401231600000, 130.58], [1401318000000, 17.12], [1401404400000, 133.52], [1401490800000, 111.67], [1401577200000, 0.02], [1401663600000, 640.63], [1401750000000, 565.65], [1401836400000, 646.74], [1401922800000, 639.96], [1402009200000, 798.42], [1402095600000, 493.09], [1402182000000, 65.13], [1402268400000, 380.07], [1402354800000, 17.01], [1402441200000, 388.32], [1402527600000, 0], [1402614000000, 0], [1402700400000, 0], [1402786800000, 0], [1402873200000, 0]], "bar": ["true"], "key": ["Revenue"]}, {"values": [[1400281200000, 25562], [1400367600000, 65], [1400454000000, 232339], [1400540400000, 225068], [1400626800000, 225401], [1400713200000, 198695], [1400799600000, 257652], [1400886000000, 14543], [1400972400000, 92], [1401058800000, 295177], [1401145200000, 980922], [1401231600000, 467542], [1401318000000, 70453], [1401404400000, 369460], [1401490800000, 307402], [1401577200000, 84], [1401663600000, 1814630], [1401750000000, 1578658], [1401836400000, 1799965], [1401922800000, 2344407], [1402009200000, 2540328], [1402095600000, 1345970], [1402182000000, 21832], [1402268400000, 1010094], [1402354800000, 66511], [1402441200000, 1078292], [1402527600000, 0], [1402614000000, 0], [1402700400000, 0], [1402786800000, 0], [1402873200000, 0]], "key": ["Duration"]}] |
468
|
|
|
|
469
|
|
|
return data |
470
|
|
|
|
471
|
|
|
@classmethod |
472
|
|
|
def get_stats_volume(cls): |
473
|
|
|
data = [] |
474
|
|
|
data1 = {'key': [], 'values': []} # , 'color': '#2ca02c' |
475
|
|
|
data2 = {'key': [], 'values': [], 'bar': 'true'} |
476
|
|
|
|
477
|
|
|
values_duration = [] |
478
|
|
|
values_total_calls = [] |
479
|
|
|
values_success_calls = [] |
480
|
|
|
|
481
|
|
|
qs_d = DimCustomerDestination.objects.all() |
482
|
|
|
#qs_h = DimCustomerHangupcause.objects.all() |
483
|
|
|
|
484
|
|
|
today = datetime.date.today() - datetime.timedelta(days=0) |
485
|
|
|
firstday = today - datetime.timedelta(days=90) |
486
|
|
|
|
487
|
|
|
ts_total_calls = time_series( |
488
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_calls')) |
489
|
|
|
ts_success_calls = time_series( |
490
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('success_calls')) |
491
|
|
|
stats_duration = time_series( |
492
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_duration')) |
493
|
|
|
|
494
|
|
|
for i in range(len(stats_duration)): |
495
|
|
|
temp_data = [ |
496
|
|
|
int(time.mktime(stats_duration[i][0].timetuple()) * 1000), |
497
|
|
|
int(round_value(ts_total_calls[i][1]))] |
498
|
|
|
|
499
|
|
|
values_total_calls.append(temp_data) |
500
|
|
|
|
501
|
|
|
data1['key'].append("Total calls") |
502
|
|
|
data1['values'] = values_total_calls |
503
|
|
|
data.append(data1) |
504
|
|
|
|
505
|
|
|
for i in range(len(stats_duration)): |
506
|
|
|
temp_data = [ |
507
|
|
|
int(time.mktime(stats_duration[i][0].timetuple()) * 1000), |
508
|
|
|
int(round_value(ts_success_calls[i][1]))] |
509
|
|
|
|
510
|
|
|
values_success_calls.append(temp_data) |
511
|
|
|
|
512
|
|
|
data2['values'] = values_success_calls |
513
|
|
|
# data2['bar'].append('true') |
514
|
|
|
data2['key'].append("Success calls") |
515
|
|
|
data.append(data2) |
516
|
|
|
|
517
|
|
|
return data |
518
|
|
|
|
519
|
|
|
@classmethod |
520
|
|
|
def get_stats_minute(cls): |
521
|
|
|
data = [] |
522
|
|
|
data1 = {'key': [], 'values': []} |
523
|
|
|
data2 = {'key': [], 'bar': 'true', 'values': []} |
524
|
|
|
|
525
|
|
|
values_duration = [] |
526
|
|
|
values_acd = [] |
527
|
|
|
acd = [] |
528
|
|
|
|
529
|
|
|
qs_d = DimCustomerDestination.objects.all() |
530
|
|
|
# qs_h = DimCustomerHangupcause.objects.all() |
531
|
|
|
|
532
|
|
|
today = datetime.date.today() - datetime.timedelta(days=0) |
533
|
|
|
firstday = today - datetime.timedelta(days=90) |
534
|
|
|
|
535
|
|
|
ts_success_calls = time_series( |
536
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('success_calls')) |
537
|
|
|
stats_duration = time_series( |
538
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_duration')) |
539
|
|
|
|
540
|
|
|
for i in range(len(stats_duration)): |
541
|
|
|
if stats_duration[i][1]: |
542
|
|
|
acd.append(stats_duration[i][1] / ts_success_calls[i][1]) |
543
|
|
|
else: |
544
|
|
|
acd.append(0) |
545
|
|
|
temp_data = [ |
546
|
|
|
int(time.mktime(stats_duration[i][0].timetuple()) * 1000), |
547
|
|
|
acd[i]] |
548
|
|
|
|
549
|
|
|
values_acd.append(temp_data) |
550
|
|
|
|
551
|
|
|
data1['key'].append("ACD in seconds") |
552
|
|
|
data1['values'] = values_acd |
553
|
|
|
data.append(data1) |
554
|
|
|
|
555
|
|
|
for i in range(len(stats_duration)): |
556
|
|
|
temp_data = [ |
557
|
|
|
int(time.mktime(stats_duration[i][0].timetuple()) * 1000), |
558
|
|
|
int(round_value(stats_duration[i][1]) / 60)] |
559
|
|
|
|
560
|
|
|
values_duration.append(temp_data) |
561
|
|
|
|
562
|
|
|
data2['values'] = values_duration |
563
|
|
|
# data2['bar'].append('true') |
564
|
|
|
data2['key'].append("Volume in minutes") |
565
|
|
|
data.append(data2) |
566
|
|
|
|
567
|
|
|
return data |
568
|
|
|
|
569
|
|
|
|
570
|
|
|
@staff_member_required |
571
|
|
|
def chart_stats_general_json(request): |
572
|
|
|
# Function to get stats for graphics |
573
|
|
|
data = [] |
574
|
|
|
params = request.GET |
575
|
|
|
name = params.get('name', '') |
576
|
|
|
if name == 'revenue': |
577
|
|
|
data = ChartData.get_stats_revenue() |
578
|
|
|
elif name == 'volume': |
579
|
|
|
data = ChartData.get_stats_volume() |
580
|
|
|
elif name == 'minute': |
581
|
|
|
data = ChartData.get_stats_minute() |
582
|
|
|
|
583
|
|
|
return HttpResponse(json.dumps(data), content_type='application/json') |
584
|
|
|
|
585
|
|
|
|
586
|
|
|
@user_passes_test(lambda u: u.is_superuser) |
587
|
|
|
@staff_member_required |
588
|
|
|
def general_stats(request): |
589
|
|
|
company_list = Company.objects.all() |
590
|
|
|
# filter(customer_enabled=True) |
591
|
|
|
datas['companies'] = company_list |
592
|
|
|
context = datas |
593
|
|
|
return render(request, 'snippets/general_stats.html', context) |
594
|
|
|
|
595
|
|
|
|
596
|
|
|
@staff_member_required |
597
|
|
|
def companies_list(): |
598
|
|
|
company_list = Company.objects.all() |
599
|
|
|
# filter(customer_enabled=True) |
600
|
|
|
return {'companies': company_list} |
601
|
|
|
|
602
|
|
|
|
603
|
|
View Code Duplication |
@user_passes_test(lambda u: u.is_superuser) |
|
|
|
|
604
|
|
|
@staff_member_required |
605
|
|
|
def admin_report_view(request): |
606
|
|
|
# view code |
607
|
|
|
qs_d = DimCustomerDestination.objects.all() |
608
|
|
|
qs_h = DimCustomerHangupcause.objects.all() |
609
|
|
|
|
610
|
|
|
# qss_total_calls = qsstats.QuerySetStats(qs, 'date__date', aggregate=Sum('total_calls')) |
611
|
|
|
# qss_success_calls = qsstats.QuerySetStats(qs, 'date__date', aggregate=Sum('success_calls')) |
612
|
|
|
# qss_total_duration = qsstats.QuerySetStats(qs, 'date__date', aggregate=Sum('total_duration')) |
613
|
|
|
# qss_total_sell = qsstats.QuerySetStats(qs, 'date__date', aggregate=Sum('total_sell')) |
614
|
|
|
# qss_total_cost = qsstats.QuerySetStats(qs, 'date__date', aggregate=Sum('total_cost')) |
615
|
|
|
|
616
|
|
|
today = datetime.date.today() |
617
|
|
|
firstday = today - datetime.timedelta(days=7) |
618
|
|
|
|
619
|
|
|
ts_total_calls = time_series( |
620
|
|
|
qs_h, 'date__date', [firstday, today], func=Sum('total_calls')) |
621
|
|
|
ts_success_calls = time_series( |
622
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('success_calls')) |
623
|
|
|
ts_total_duration = time_series( |
624
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_duration')) |
625
|
|
|
ts_total_sell = time_series( |
626
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_sell')) |
627
|
|
|
ts_total_cost = time_series( |
628
|
|
|
qs_d, 'date__date', [firstday, today], func=Sum('total_cost')) |
629
|
|
|
ts_total_margin = _margin_series(ts_total_sell, ts_total_cost) |
630
|
|
|
|
631
|
|
|
return render(request, 'admin/admin_report.html', locals()) |
632
|
|
|
|