|
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
|
|
|
|