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.db import models |
18
|
|
|
from django.db.models import permalink, Sum, Avg, Count, Max, Min |
19
|
|
|
from django.core.validators import EMPTY_VALUES |
20
|
|
|
from django.core.exceptions import ValidationError |
21
|
|
|
from django.conf import settings |
22
|
|
|
from django.contrib.contenttypes import generic |
23
|
|
|
from django.contrib.contenttypes.models import ContentType |
24
|
|
|
from django.contrib.contenttypes.generic import GenericRelation |
25
|
|
|
from django.utils.translation import ugettext_lazy as _ |
26
|
|
|
from django.utils.html import format_html |
27
|
|
|
|
28
|
|
|
import datetime |
29
|
|
|
import qsstats |
30
|
|
|
import vatnumber |
31
|
|
|
|
32
|
|
|
import decimal |
33
|
|
|
|
34
|
|
|
import math |
35
|
|
|
|
36
|
|
|
from django_countries.fields import CountryField |
37
|
|
|
|
38
|
|
|
from netaddr import IPNetwork, AddrFormatError |
39
|
|
|
|
40
|
|
|
import re |
41
|
|
|
|
42
|
|
|
from currencies.models import Currency |
43
|
|
|
|
44
|
|
|
from pyfreebill.validators import validate_cidr |
45
|
|
|
|
46
|
|
|
# CustomUser -- Django 1.6 |
47
|
|
|
# class CustomUser(AbstractUser): |
48
|
|
|
# keyboard_shortcuts = models.BooleanField(default=True) |
49
|
|
|
|
50
|
|
|
# Finance |
51
|
|
|
from django.core.exceptions import ValidationError |
52
|
|
|
|
53
|
|
|
|
54
|
|
|
def check_vat(value): |
55
|
|
|
if value != "" and not vatnumber.check_vat(value): |
56
|
|
|
raise ValidationError(_(u"%s is not a valid VAT number") % value) |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
class Company(models.Model): |
60
|
|
|
"""Company model.""" |
61
|
|
|
name = models.CharField(_(u'name'), |
62
|
|
|
max_length=200, |
63
|
|
|
unique=True) |
64
|
|
|
nickname = models.CharField(_(u'nickname'), |
65
|
|
|
max_length=50, |
66
|
|
|
blank=True, |
67
|
|
|
null=True) |
68
|
|
|
slug = models.SlugField(_(u'slug'), |
69
|
|
|
max_length=50, |
70
|
|
|
unique=True) |
71
|
|
|
about = models.CharField(_(u'about'), |
72
|
|
|
max_length=250, |
73
|
|
|
blank=True, |
74
|
|
|
null=True) |
75
|
|
|
phone_number = GenericRelation(u'PhoneNumber') |
76
|
|
|
email_address = GenericRelation(u'EmailAddress') |
77
|
|
|
web_site = GenericRelation(u'WebSite') |
78
|
|
|
street_address = GenericRelation(u'StreetAddress') |
79
|
|
|
account_number = models.IntegerField(_(u"Account number"), |
80
|
|
|
blank=True, |
81
|
|
|
null=True) |
82
|
|
|
vat = models.BooleanField(_(u"VAT Applicable / Not applicable"), |
83
|
|
|
default=False, |
84
|
|
|
help_text=_(u"if checked, VAT is applicable.")) |
85
|
|
|
vat_number = models.CharField(_(u"VAT number"), |
86
|
|
|
max_length=30, |
87
|
|
|
blank=True, |
88
|
|
|
validators=[check_vat]) |
89
|
|
|
vat_number_validated = models.BooleanField(_(u"VAT Vies Validated."), |
90
|
|
|
default=False, |
91
|
|
|
help_text=_(u"If on, it means that VAT is " |
92
|
|
|
u"validated through <a target='_blank' " |
93
|
|
|
u"href='http://ec.europa.eu/taxation_customs/vies/vatRequest.html'>Vies</a>.")) |
94
|
|
|
prepaid = models.BooleanField(_(u"Prepaid / Postpaid"), |
95
|
|
|
default=True, |
96
|
|
|
help_text=_(u"If checked, this account customer is prepaid.")) |
97
|
|
|
credit_limit = models.DecimalField(_(u'credit limit'), |
98
|
|
|
max_digits=12, |
99
|
|
|
decimal_places=4, |
100
|
|
|
default=0, |
101
|
|
|
help_text=_(u"Credit limit for postpaid account.")) |
102
|
|
|
low_credit_alert = models.DecimalField(_(u'low credit level alert'), |
103
|
|
|
max_digits=12, |
104
|
|
|
decimal_places=4, |
105
|
|
|
default="10", |
106
|
|
|
help_text=_(u"Low credit limit alert.")) |
107
|
|
|
low_credit_alert_sent = models.BooleanField(_(u"low credit alert ON"), |
108
|
|
|
default=False) |
109
|
|
|
account_blocked_alert_sent = models.BooleanField(_(u"Customer account blocked - low balance - ON"), |
110
|
|
|
default=False) |
111
|
|
|
email_alert = models.EmailField(_(u'alert email address'), |
112
|
|
|
blank=True, |
113
|
|
|
null=True) |
114
|
|
|
customer_balance = models.DecimalField(_(u'customer balance'), |
115
|
|
|
max_digits=12, |
116
|
|
|
decimal_places=6, |
117
|
|
|
default=0, |
118
|
|
|
help_text=_(u"Actual customer balance.")) |
119
|
|
|
cb_currency = models.ForeignKey(Currency, |
120
|
|
|
verbose_name=_(u"Currency")) |
121
|
|
|
supplier_balance = models.DecimalField(_(u'supplier balance'), |
122
|
|
|
max_digits=12, |
123
|
|
|
decimal_places=6, |
124
|
|
|
default=0, |
125
|
|
|
help_text=_(u"Actual supplier balance.")) |
126
|
|
|
max_calls = models.PositiveIntegerField(_(u'max simultaneous calls'), |
127
|
|
|
default=1, |
128
|
|
|
help_text=_(u"maximum simultaneous calls allowed for this customer account.")) |
129
|
|
|
calls_per_second = models.PositiveIntegerField( |
130
|
|
|
_(u'max calls per second'), |
131
|
|
|
default=10, |
132
|
|
|
help_text=_(u"maximum calls per seconds allowed for this customer account.") |
133
|
|
|
) |
134
|
|
|
BILLING_CYCLE_CHOICES = ( |
135
|
|
|
('w', _(u'weekly')), |
136
|
|
|
('m', _(u'monthly')), |
137
|
|
|
) |
138
|
|
|
billing_cycle = models.CharField( |
139
|
|
|
_(u'billing cycle'), |
140
|
|
|
max_length=10, |
141
|
|
|
choices=BILLING_CYCLE_CHOICES, |
142
|
|
|
default='m', |
143
|
|
|
help_text=_(u"billinng cycle for invoice generation.") |
144
|
|
|
) |
145
|
|
|
customer_enabled = models.BooleanField(_(u"Customer Enabled / Disabled"), |
146
|
|
|
default=True) |
147
|
|
|
supplier_enabled = models.BooleanField(_(u"Supplier Enabled / Disabled"), |
148
|
|
|
default=True) |
149
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
150
|
|
|
auto_now_add=True) |
151
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
152
|
|
|
auto_now=True) |
153
|
|
|
|
154
|
|
|
class Meta: |
155
|
|
|
db_table = 'company' |
156
|
|
|
ordering = ('name',) |
157
|
|
|
verbose_name = _(u"Company") |
158
|
|
|
verbose_name_plural = _(u"Companies") |
159
|
|
|
|
160
|
|
|
def clean(self): |
161
|
|
|
if self.vat_number: |
162
|
|
|
try: |
163
|
|
|
vatnumber.check_vies(self.vat_number) |
164
|
|
|
except Exception, e: |
165
|
|
|
raise ValidationError(_(u"""Wrong VAT number - validation made throw VIES services. %s""")) % e |
166
|
|
|
|
167
|
|
|
def save(self, *args, **kwargs): |
168
|
|
|
if self.vat_number: |
169
|
|
|
try: |
170
|
|
|
self.vat_number_validated = vatnumber.check_vies(self.vat_number) |
171
|
|
|
except: |
172
|
|
|
self.vat_number_validated = False |
173
|
|
|
else: |
174
|
|
|
self.vat_number_validated = False |
175
|
|
|
|
176
|
|
|
super(Company, self).save(*args, **kwargs) |
177
|
|
|
|
178
|
|
|
def __unicode__(self): |
179
|
|
|
return u"%s" % self.name |
180
|
|
|
|
181
|
|
|
def colored_name(self): |
182
|
|
|
if self.customer_enabled == False and self.supplier_enabled == False: |
183
|
|
|
color = "red" |
184
|
|
|
elif self.customer_enabled == False and self.supplier_enabled == True: |
185
|
|
|
color = "orange" |
186
|
|
|
elif self.customer_enabled == True and self.supplier_enabled == False: |
187
|
|
|
color = "purple" |
188
|
|
|
else: |
189
|
|
|
color = "green" |
190
|
|
|
return " <span style=color:%s>%s</span>" % (color, self.name) |
191
|
|
|
colored_name.allow_tags = True |
192
|
|
|
|
193
|
|
|
def balance_history(self): |
194
|
|
|
html = '<span><a href="/extranet/pyfreebill/companybalancehistory/?company__id__exact={0}" class="btn btn-inverse btn-mini">Balance history <i class="icon-plus-sign"></i></a></span>' |
195
|
|
|
return format_html(html, (self.id)) |
196
|
|
|
balance_history.allow_tags = True |
197
|
|
|
balance_history.short_description = _(u'balance history') |
198
|
|
|
|
199
|
|
|
|
200
|
|
|
class Person(models.Model): |
201
|
|
|
"""Person model.""" |
202
|
|
|
first_name = models.CharField(_(u'first name'), |
203
|
|
|
max_length=100) |
204
|
|
|
last_name = models.CharField(_(u'last name'), |
205
|
|
|
max_length=200) |
206
|
|
|
middle_name = models.CharField(_(u'middle name'), |
207
|
|
|
max_length=200, |
208
|
|
|
blank=True, |
209
|
|
|
null=True) |
210
|
|
|
suffix = models.CharField(_(u'suffix'), |
211
|
|
|
max_length=50, |
212
|
|
|
blank=True, |
213
|
|
|
null=True) |
214
|
|
|
nickname = models.CharField(_(u'nickname'), |
215
|
|
|
max_length=100, |
216
|
|
|
blank=True) |
217
|
|
|
slug = models.SlugField(_(u'slug'), |
218
|
|
|
max_length=50, |
219
|
|
|
unique=True) |
220
|
|
|
title = models.CharField(_(u'title'), |
221
|
|
|
max_length=200, |
222
|
|
|
blank=True) |
223
|
|
|
company = models.ForeignKey(Company, |
224
|
|
|
blank=True, |
225
|
|
|
null=True) |
226
|
|
|
about = models.TextField(_(u'about'), |
227
|
|
|
blank=True) |
228
|
|
|
user = models.OneToOneField( |
229
|
|
|
settings.AUTH_USER_MODEL, |
230
|
|
|
on_delete=models.CASCADE, |
231
|
|
|
blank=True, |
232
|
|
|
null=True, |
233
|
|
|
verbose_name=_(u'user')) |
234
|
|
|
phone_number = GenericRelation('PhoneNumber') |
235
|
|
|
date_added = models.DateTimeField(_('date added'), |
236
|
|
|
auto_now_add=True) |
237
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
238
|
|
|
auto_now=True) |
239
|
|
|
|
240
|
|
|
class Meta: |
241
|
|
|
db_table = 'contacts_people' |
242
|
|
|
ordering = ('last_name', 'first_name') |
243
|
|
|
verbose_name = _(u'person') |
244
|
|
|
verbose_name_plural = _(u'people') |
245
|
|
|
|
246
|
|
|
def __unicode__(self): |
247
|
|
|
return self.fullname |
248
|
|
|
|
249
|
|
|
@property |
250
|
|
|
def fullname(self): |
251
|
|
|
return u"%s %s" % (self.first_name, self.last_name) |
252
|
|
|
|
253
|
|
|
|
254
|
|
|
class Group(models.Model): |
255
|
|
|
"""Group model.""" |
256
|
|
|
name = models.CharField(_(u'name'), |
257
|
|
|
max_length=200, |
258
|
|
|
unique=True) |
259
|
|
|
slug = models.SlugField(_(u'slug'), |
260
|
|
|
max_length=50, |
261
|
|
|
unique=True) |
262
|
|
|
about = models.TextField(_(u'about'), |
263
|
|
|
blank=True) |
264
|
|
View Code Duplication |
people = models.ManyToManyField(Person, |
|
|
|
|
265
|
|
|
verbose_name=_(u'people'), |
266
|
|
|
blank=True, |
267
|
|
|
null=True) |
268
|
|
|
companies = models.ManyToManyField(Company, |
269
|
|
|
verbose_name=_(u'companies'), |
270
|
|
|
blank=True, |
271
|
|
|
null=True) |
272
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
273
|
|
|
auto_now_add=True) |
274
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
275
|
|
|
auto_now=True) |
276
|
|
|
|
277
|
|
|
class Meta: |
278
|
|
|
db_table = 'contacts_groups' |
279
|
|
|
ordering = ('name',) |
280
|
|
|
verbose_name = _(u'group') |
281
|
|
|
verbose_name_plural = _(u'groups') |
282
|
|
|
|
283
|
|
|
def __unicode__(self): |
284
|
|
|
return u"%s" % self.name |
285
|
|
|
|
286
|
|
|
|
287
|
|
|
PHONE_LOCATION_CHOICES = ( |
288
|
|
|
('work', _(u'Work')), |
289
|
|
|
('mobile', _(u'Mobile')), |
290
|
|
|
('fax', _(u'Fax')), |
291
|
|
|
('pager', _(u'Pager')), |
292
|
|
|
('home', _(u'Home')), |
293
|
|
|
('other', _(u'Other')), |
294
|
|
|
) |
295
|
|
|
|
296
|
|
|
|
297
|
|
|
class PhoneNumber(models.Model): |
298
|
|
|
"""Phone Number model.""" |
299
|
|
|
content_type = models.ForeignKey( |
300
|
|
|
ContentType, |
301
|
|
|
limit_choices_to={'app_label': 'contacts'}) |
302
|
|
|
object_id = models.IntegerField(db_index=True) |
303
|
|
|
content_object = generic.GenericForeignKey() |
304
|
|
|
phone_number = models.CharField(_(u'number'), |
305
|
|
|
max_length=50) |
306
|
|
|
location = models.CharField(_(u'location'), |
307
|
|
|
max_length=6, |
308
|
|
|
choices=PHONE_LOCATION_CHOICES, |
309
|
|
|
default='work') |
310
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
311
|
|
|
auto_now_add=True) |
312
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
313
|
|
|
auto_now=True) |
314
|
|
|
|
315
|
|
|
def __unicode__(self): |
316
|
|
|
return u"%s (%s)" % (self.phone_number, self.location) |
317
|
|
|
|
318
|
|
|
class Meta: |
319
|
|
|
db_table = 'contacts_phone_numbers' |
320
|
|
|
verbose_name = _(u'phone number') |
321
|
|
|
verbose_name_plural = _(u'phone numbers') |
322
|
|
|
|
323
|
|
|
|
324
|
|
|
LOCATION_CHOICES = ( |
325
|
|
|
('work', _(u'Work')), |
326
|
|
|
('home', _(u'Home')), |
327
|
|
|
('mobile', _(u'Mobile')), |
328
|
|
|
('fax', _(u'Fax')), |
329
|
|
|
('person', _(u'Personal')), |
330
|
|
|
('other', _(u'Other')) |
331
|
|
|
) |
332
|
|
|
|
333
|
|
|
|
334
|
|
|
class EmailAddress(models.Model): |
335
|
|
|
content_type = models.ForeignKey( |
336
|
|
|
ContentType, |
337
|
|
|
limit_choices_to={'app_label': 'contacts'}) |
338
|
|
|
object_id = models.IntegerField(db_index=True) |
339
|
|
|
content_object = generic.GenericForeignKey() |
340
|
|
|
email_address = models.EmailField(_(u'email address')) |
341
|
|
|
location = models.CharField(_(u'location'), |
342
|
|
|
max_length=6, |
343
|
|
|
choices=LOCATION_CHOICES, |
344
|
|
|
default='work') |
345
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
346
|
|
|
auto_now_add=True) |
347
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
348
|
|
|
auto_now=True) |
349
|
|
|
|
350
|
|
|
def __unicode__(self): |
351
|
|
|
return u"%s (%s)" % (self.email_address, self.location) |
352
|
|
|
|
353
|
|
|
class Meta: |
354
|
|
|
db_table = 'contacts_email_addresses' |
355
|
|
|
verbose_name = _(u'email address') |
356
|
|
|
verbose_name_plural = _(u'email addresses') |
357
|
|
|
|
358
|
|
|
|
359
|
|
|
IM_SERVICE_CHOICES = ( |
360
|
|
|
('aim', 'AIM'), |
361
|
|
|
('msn', 'MSN'), |
362
|
|
|
('icq', 'ICQ'), |
363
|
|
|
('jabber', 'Jabber'), |
364
|
|
|
('yahoo', 'Yahoo'), |
365
|
|
|
('skype', 'Skype'), |
366
|
|
|
('qq', 'QQ'), |
367
|
|
|
('sametime', 'Sametime'), |
368
|
|
|
('gadu-gadu', 'Gadu-Gadu'), |
369
|
|
|
('google-talk', 'Google Talk'), |
370
|
|
|
('twitter', 'Twitter'), |
371
|
|
|
('other', _(u'Other')) |
372
|
|
|
) |
373
|
|
|
|
374
|
|
|
|
375
|
|
|
class WebSite(models.Model): |
376
|
|
|
content_type = models.ForeignKey( |
377
|
|
|
ContentType, |
378
|
|
|
limit_choices_to={'app_label': 'contacts'}) |
379
|
|
|
object_id = models.IntegerField(db_index=True) |
380
|
|
|
content_object = generic.GenericForeignKey() |
381
|
|
|
url = models.URLField(_(u'URL')) |
382
|
|
|
location = models.CharField(_(u'location'), |
383
|
|
|
max_length=6, |
384
|
|
|
choices=LOCATION_CHOICES, |
385
|
|
|
default='work') |
386
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
387
|
|
|
auto_now_add=True) |
388
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
389
|
|
|
auto_now=True) |
390
|
|
|
|
391
|
|
|
def __unicode__(self): |
392
|
|
|
return u"%s (%s)" % (self.url, self.location) |
393
|
|
|
|
394
|
|
|
class Meta: |
395
|
|
|
db_table = 'contacts_web_sites' |
396
|
|
|
verbose_name = _(u'web site') |
397
|
|
|
verbose_name_plural = _(u'web sites') |
398
|
|
|
|
399
|
|
|
def get_absolute_url(self): |
400
|
|
|
return u"%s?web_site=%s" % (self.content_object.get_absolute_url(), self.pk) |
401
|
|
|
|
402
|
|
|
|
403
|
|
|
class StreetAddress(models.Model): |
404
|
|
|
content_type = models.ForeignKey( |
405
|
|
|
ContentType, |
406
|
|
|
limit_choices_to={'app_label': 'contacts'}) |
407
|
|
|
object_id = models.IntegerField(db_index=True) |
408
|
|
|
content_object = generic.GenericForeignKey() |
409
|
|
|
street = models.TextField(_(u'street'), |
410
|
|
|
blank=True) |
411
|
|
|
city = models.CharField(_(u'city'), |
412
|
|
|
max_length=200, |
413
|
|
|
blank=True) |
414
|
|
|
province = models.CharField(_(u'province'), |
415
|
|
|
max_length=200, |
416
|
|
|
blank=True) |
417
|
|
|
postal_code = models.CharField(_(u'postal code'), |
418
|
|
|
max_length=10, |
419
|
|
|
blank=True) |
420
|
|
|
country = CountryField(_(u'country')) |
421
|
|
|
location = models.CharField(_(u'location'), |
422
|
|
|
max_length=6, |
423
|
|
|
choices=LOCATION_CHOICES, |
424
|
|
|
default='work') |
425
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
426
|
|
|
auto_now_add=True) |
427
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
428
|
|
|
auto_now=True) |
429
|
|
|
|
430
|
|
|
def __unicode__(self): |
431
|
|
|
return u"%s (%s)" % (self.city, self.location) |
432
|
|
|
|
433
|
|
|
class Meta: |
434
|
|
|
db_table = 'contacts_street_addresses' |
435
|
|
|
verbose_name = _(u'street address') |
436
|
|
|
verbose_name_plural = _(u'street addresses') |
437
|
|
|
|
438
|
|
|
|
439
|
|
|
class CompanyBalanceHistory(models.Model): |
440
|
|
|
""" Company balance history Model """ |
441
|
|
|
company = models.ForeignKey(Company, |
442
|
|
|
verbose_name=_(u"company")) |
443
|
|
|
amount_debited = models.DecimalField(_(u'amount debited'), |
444
|
|
|
max_digits=12, |
445
|
|
|
decimal_places=4) |
446
|
|
|
amount_refund = models.DecimalField(_(u'amount refund'), |
447
|
|
|
max_digits=12, |
448
|
|
|
decimal_places=4) |
449
|
|
|
customer_balance = models.DecimalField(_(u'customer balance'), |
450
|
|
|
max_digits=12, |
451
|
|
|
decimal_places=4, |
452
|
|
|
default=0, |
453
|
|
|
help_text=_(u"""Resulting customer |
454
|
|
|
balance.""")) |
455
|
|
|
supplier_balance = models.DecimalField(_(u'provider balance'), |
456
|
|
|
max_digits=12, |
457
|
|
|
decimal_places=4, |
458
|
|
|
default=0, |
459
|
|
|
help_text=_(u"""Resulting provider |
460
|
|
|
balance.""")) |
461
|
|
|
OPERATION_TYPE_CHOICES = ( |
462
|
|
|
('customer', _(u"operation on customer account")), |
463
|
|
|
('provider', _(u"operation on provider account")), |
464
|
|
|
) |
465
|
|
|
operation_type = models.CharField(_(u"operation type"), |
466
|
|
|
max_length=10, |
467
|
|
|
choices=OPERATION_TYPE_CHOICES, |
468
|
|
|
default='customer') |
469
|
|
|
reference = models.CharField(_(u'public description'), |
470
|
|
|
max_length=255, |
471
|
|
|
blank=True) |
472
|
|
|
description = models.CharField(_(u'internal description'), |
473
|
|
|
max_length=255, |
474
|
|
|
blank=True) |
475
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
476
|
|
|
auto_now_add=True) |
477
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
478
|
|
|
auto_now=True) |
479
|
|
|
|
480
|
|
|
class Meta: |
481
|
|
|
db_table = 'company_balance_history' |
482
|
|
|
ordering = ('company', 'date_added') |
483
|
|
|
verbose_name = _(u'Company balance history') |
484
|
|
|
verbose_name_plural = _(u'Company balance history') |
485
|
|
|
|
486
|
|
|
def __unicode__(self): |
487
|
|
|
return u"%s %s %s %s" % (self.company, |
488
|
|
|
self.amount_debited, |
489
|
|
|
self.amount_refund, |
490
|
|
|
self.operation_type) |
491
|
|
|
|
492
|
|
|
|
493
|
|
|
class CustomerDirectory(models.Model): |
494
|
|
|
""" Customer Directory Model """ |
495
|
|
|
company = models.ForeignKey(Company, |
496
|
|
|
verbose_name=_(u"company")) |
497
|
|
|
registration = models.BooleanField(_(u"Registration"), |
498
|
|
|
default=False, |
499
|
|
|
help_text=_(u"""Is registration needed |
500
|
|
|
for calling ? True, the phone needs to |
501
|
|
|
register with correct username/password. |
502
|
|
|
If false, you must specify a CIDR in SIP |
503
|
|
|
IP CIDR !""")) |
504
|
|
|
password = models.CharField(_(u"password"), |
505
|
|
|
max_length=100, |
506
|
|
|
blank=True, |
507
|
|
|
help_text=_(u"""It's recommended to use strong |
508
|
|
|
passwords for the endpoint.""")) |
509
|
|
|
description = models.TextField(_(u'description'), |
510
|
|
|
blank=True) |
511
|
|
|
name = models.CharField(_(u"SIP username"), |
512
|
|
|
max_length=50, |
513
|
|
|
unique=True, |
514
|
|
|
help_text=_(u"Ex.: customer SIP username, etc...")) |
515
|
|
|
rtp_ip = models.CharField(_(u"RTP IP CIDR"), |
516
|
|
|
max_length=100, |
517
|
|
|
default="auto", |
518
|
|
|
help_text=_(u"""Internal IP address/mask to bind |
519
|
|
|
to for RTP. Format : CIDR Ex. 192.168.1.0/32""")) |
520
|
|
|
sip_ip = models.CharField(_(u"SIP IP CIDR"), |
521
|
|
|
max_length=100, |
522
|
|
|
null=True, |
523
|
|
|
blank=True, |
524
|
|
|
validators=[validate_cidr], |
525
|
|
|
help_text=_(u"""Internal IP address/mask to bind |
526
|
|
|
to for SIP. Format : CIDR. Ex. 192.168.1.0/32 |
527
|
|
|
""")) |
528
|
|
|
sip_port = models.PositiveIntegerField(_(u"SIP port"), |
529
|
|
|
default=5060) |
530
|
|
|
max_calls = models.PositiveIntegerField(_(u'max calls'), |
531
|
|
|
default=1, |
532
|
|
|
help_text=_(u"""max simultaneous |
533
|
|
|
calls allowed for this customer |
534
|
|
|
account.""")) |
535
|
|
|
calls_per_second = models.PositiveIntegerField(_(u'max calls per second'), |
536
|
|
|
default=10, |
537
|
|
|
help_text=_(u"""maximum |
538
|
|
|
calls per second allowed for |
539
|
|
|
this customer account.""")) |
540
|
|
|
log_auth_failures = models.BooleanField(_(u"log auth failures"), |
541
|
|
|
default=False, |
542
|
|
|
help_text=_(u"""It true, the server |
543
|
|
|
will log authentication failures. |
544
|
|
|
Required for Fail2ban.""")) |
545
|
|
|
MULTIPLE_CODECS_CHOICES = ( |
546
|
|
|
("PCMA,PCMU,G729", _(u"PCMA,PCMU,G729")), |
547
|
|
|
("PCMU,PCMA,G729", _(u"PCMU,PCMA,G729")), |
548
|
|
|
("G729,PCMA,PCMU", _(u"G729,PCMA,PCMU")), |
549
|
|
|
("G729,PCMU,PCMA", _(u"G729,PCMU,PCMA")), |
550
|
|
|
("PCMA,G729", _(u"PCMA,G729")), |
551
|
|
|
("PCMU,G729", _(u"PCMU,G729")), |
552
|
|
|
("G729,PCMA", _(u"G729,PCMA")), |
553
|
|
|
("G729,PCMU", _(u"G729,PCMU")), |
554
|
|
|
("PCMA,PCMU", _(u"PCMA,PCMU")), |
555
|
|
|
("PCMU,PCMA", _(u"PCMU,PCMA")), |
556
|
|
|
("G722,PCMA,PCMU", _(u"G722,PCMA,PCMU")), |
557
|
|
|
("G722,PCMU,PCMA", _(u"G722,PCMU,PCMA")), |
558
|
|
|
("G722", _(u"G722")), |
559
|
|
|
("G729", _(u"G729")), |
560
|
|
|
("PCMU", _(u"PCMU")), |
561
|
|
|
("PCMA", _(u"PCMA")), |
562
|
|
|
("ALL", _(u"ALL")), |
563
|
|
|
) |
564
|
|
|
codecs = models.CharField(_(u"Codecs"), |
565
|
|
|
max_length=100, |
566
|
|
|
default="ALL", |
567
|
|
|
choices=MULTIPLE_CODECS_CHOICES, |
568
|
|
|
help_text=_(u"""Codecs allowed - beware about |
569
|
|
|
order, 1st has high priority """)) |
570
|
|
|
MULTIPLE_REG_CHOICES = ( |
571
|
|
|
("call-id", _(u"Call-id")), |
572
|
|
|
("contact", _(u"Contact")), |
573
|
|
|
("false", _(u"False")), |
574
|
|
|
("true", _(u"True"))) |
575
|
|
|
multiple_registrations = models.CharField(_(u"multiple registrations"), |
576
|
|
|
max_length=100, |
577
|
|
|
default="false", |
578
|
|
|
choices=MULTIPLE_REG_CHOICES, |
579
|
|
|
help_text=_(u"""Used to allow to |
580
|
|
|
call one extension and ring |
581
|
|
|
several phones.""")) |
582
|
|
|
outbound_caller_id_name = models.CharField(_(u"CallerID name"), |
583
|
|
|
max_length=50, |
584
|
|
|
blank=True, |
585
|
|
|
help_text=_(u"""Caller ID name |
586
|
|
|
sent to provider on outbound |
587
|
|
|
calls.""")) |
588
|
|
|
outbound_caller_id_number = models.CharField(_(u"""CallerID |
589
|
|
|
num"""), |
590
|
|
|
max_length=80, |
591
|
|
|
blank=True, |
592
|
|
|
help_text=_(u"""Caller ID |
593
|
|
|
number sent to provider on |
594
|
|
|
outbound calls.""")) |
595
|
|
|
IEM_CHOICES = ( |
596
|
|
|
("false", _(u"false")), |
597
|
|
|
("true", _(u"true")), |
598
|
|
|
("ring_ready", _(u"ring_ready"))) |
599
|
|
|
ignore_early_media = models.CharField(_(u"Ignore early media"), |
600
|
|
|
max_length=20, |
601
|
|
|
default="false", |
602
|
|
|
choices=IEM_CHOICES, |
603
|
|
|
help_text=_(u"""Controls if the call |
604
|
|
|
returns on early media |
605
|
|
|
or not. Default is false. |
606
|
|
|
Setting the value to |
607
|
|
|
"ring_ready" will work |
608
|
|
|
the same as |
609
|
|
|
ignore_early_media=true |
610
|
|
|
but also send a SIP 180 |
611
|
|
|
to the inbound leg when |
612
|
|
|
the first SIP 183 is |
613
|
|
|
caught. |
614
|
|
|
""")) |
615
|
|
|
enabled = models.BooleanField(_(u"Enabled / Disabled"), |
616
|
|
|
default=True) |
617
|
|
|
fake_ring = models.BooleanField(_(u"Fake ring"), |
618
|
|
|
default=False, |
619
|
|
|
help_text=_(u"""Fake ring : Enabled / |
620
|
|
|
Disabled - Send a fake ring to the |
621
|
|
|
caller.""")) |
622
|
|
|
cli_debug = models.BooleanField(_(u"CLI debug"), |
623
|
|
|
default=False, |
624
|
|
|
help_text=_(u"""CLI debug : Enabled / |
625
|
|
|
Disabled - Permit to see all debug |
626
|
|
|
messages on cli.""")) |
627
|
|
|
vmd = models.BooleanField(_(u"Voicemail detection : Enabled / Disabled"), |
628
|
|
|
default=False, |
629
|
|
|
help_text=_(u"""Be carefull with this option, as |
630
|
|
|
it takes a lot of ressources !.""")) |
631
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
632
|
|
|
auto_now_add=True) |
633
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
634
|
|
|
auto_now=True) |
635
|
|
|
|
636
|
|
|
class Meta: |
637
|
|
|
db_table = 'customer_directory' |
638
|
|
|
ordering = ('company', 'name') |
639
|
|
|
verbose_name = _(u'Customer sip account') |
640
|
|
|
verbose_name_plural = _(u'Customer sip accounts') |
641
|
|
|
|
642
|
|
|
def __unicode__(self): |
643
|
|
|
return "%s (%s:%s)" % (self.name, self.sip_ip, self.sip_port) |
644
|
|
|
|
645
|
|
|
def clean(self): |
646
|
|
|
if (self.registration and |
647
|
|
|
(self.password is None or self.password == '')): |
648
|
|
|
raise ValidationError(_(u"""You have to specify a password if you |
649
|
|
|
want to allow registration""")) |
650
|
|
|
if (self.registration is False and |
651
|
|
|
(self.sip_ip is None or self.sip_ip == '')): |
652
|
|
|
raise ValidationError(_(u"""You must specify a SIP IP CIDR if you do |
653
|
|
|
not want to use registration""")) |
654
|
|
|
if self.registration and self.password: |
655
|
|
|
# in future use https://github.com/dstufft/django-passwords ? |
656
|
|
|
MIN_LENGTH = 8 |
657
|
|
|
if len(self.password) < MIN_LENGTH: |
658
|
|
|
raise ValidationError(_(u"""The password must be at least %d |
659
|
|
|
characters long.""") % MIN_LENGTH) |
660
|
|
|
first_isalpha = self.password[0].isalpha() |
661
|
|
|
if all(c.isalpha() == first_isalpha for c in self.password): |
662
|
|
|
raise ValidationError(_(u"""The new password must contain |
663
|
|
|
at least one letter and at least |
664
|
|
|
one digit""")) |
665
|
|
|
if self.sip_ip: |
666
|
|
|
m = re.search('/32$', self.sip_ip) |
667
|
|
|
if m: |
668
|
|
|
pass |
669
|
|
|
elif len(IPNetwork(self.sip_ip)) == 1: |
670
|
|
|
self.sip_ip = str(self.sip_ip) + str('/32') |
671
|
|
|
# add name check no space ... |
672
|
|
|
|
673
|
|
|
# Caller ID list |
674
|
|
|
|
675
|
|
|
|
676
|
|
|
class CalleridPrefixList(models.Model): |
677
|
|
|
""" CallerID List """ |
678
|
|
|
name = models.CharField(_(u'name'), |
679
|
|
|
max_length=128, |
680
|
|
|
unique=True) |
681
|
|
|
description = models.TextField(_(u'description'), |
682
|
|
|
blank=True) |
683
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
684
|
|
|
auto_now_add=True) |
685
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
686
|
|
|
auto_now=True) |
687
|
|
|
|
688
|
|
|
class Meta: |
689
|
|
|
db_table = 'callerid_prefix_list' |
690
|
|
|
ordering = ('name',) |
691
|
|
|
verbose_name = _(u'CallerID prefix list') |
692
|
|
|
verbose_name_plural = _(u'CallerID prefix lists') |
693
|
|
|
|
694
|
|
|
def __unicode__(self): |
695
|
|
|
return u"%s" % self.name |
696
|
|
|
|
697
|
|
|
def prefix(self): |
698
|
|
|
html = '<span><a href="/extranet/pyfreebill/calleridprefix/?calleridprefixlist__id__exact={0}" class="btn btn-inverse btn-mini">Prefix <i class="icon-plus-sign"></i></a></span>' |
699
|
|
|
return format_html(html, (self.id)) |
700
|
|
|
prefix.allow_tags = True |
701
|
|
|
prefix.short_description = _(u'prefix') |
702
|
|
|
|
703
|
|
|
|
704
|
|
|
class CalleridPrefix(models.Model): |
705
|
|
|
""" Customer Rates Model """ |
706
|
|
|
calleridprefixlist = models.ForeignKey( |
707
|
|
|
CalleridPrefixList, |
708
|
|
|
verbose_name=_(u"callerid prefix list")) |
709
|
|
|
prefix = models.CharField(_(u'numeric prefix'), |
710
|
|
|
max_length=30, |
711
|
|
|
db_index=True) |
712
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
713
|
|
|
auto_now_add=True) |
714
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
715
|
|
|
auto_now=True) |
716
|
|
|
|
717
|
|
|
class Meta: |
718
|
|
|
db_table = 'caller_id_prefix' |
719
|
|
|
ordering = ('calleridprefixlist', 'prefix') |
720
|
|
|
unique_together = ("calleridprefixlist", "prefix") |
721
|
|
|
verbose_name = _(u'Callerid prefix') |
722
|
|
|
verbose_name_plural = _(u'Callerid prefix') |
723
|
|
|
|
724
|
|
|
def __unicode__(self): |
725
|
|
|
return u"%s" % self.prefix |
726
|
|
|
|
727
|
|
|
# Provider Rates |
728
|
|
|
|
729
|
|
|
|
730
|
|
|
class ProviderTariff(models.Model): |
731
|
|
|
""" Provider tariff """ |
732
|
|
View Code Duplication |
name = models.CharField(_(u"name"), |
|
|
|
|
733
|
|
|
max_length=128) |
734
|
|
|
carrier = models.ForeignKey(Company, |
735
|
|
|
verbose_name=_(u"Provider"), |
736
|
|
|
limit_choices_to={'supplier_enabled': True}) |
737
|
|
|
currency = models.ForeignKey( |
738
|
|
|
Currency, |
739
|
|
|
verbose_name=_(u"Currency")) |
740
|
|
|
lead_strip = models.CharField(_(u'lead strip'), |
741
|
|
|
blank=True, |
742
|
|
|
default='', |
743
|
|
|
max_length=15) |
744
|
|
|
tail_strip = models.CharField(_(u'tail strip'), |
745
|
|
|
blank=True, |
746
|
|
|
default='', |
747
|
|
|
max_length=15) |
748
|
|
|
prefix = models.CharField(_(u'prefix'), |
749
|
|
|
blank=True, |
750
|
|
|
default='', |
751
|
|
|
max_length=15) |
752
|
|
|
suffix = models.CharField(_(u'suffix'), |
753
|
|
|
blank=True, |
754
|
|
|
default='', |
755
|
|
|
max_length=15) |
756
|
|
|
description = models.TextField(_(u'description'), |
757
|
|
|
blank=True) |
758
|
|
|
CALLERID_FILTER_CHOICES = ( |
759
|
|
|
('1', _(u"No filter")), |
760
|
|
|
('2', _(u"Prefix authorized")), |
761
|
|
|
('3', _(u"Prefix prohibited")), |
762
|
|
|
) |
763
|
|
|
callerid_filter = models.CharField(_(u"CallerID Prefix filter"), |
764
|
|
|
max_length=2, |
765
|
|
|
choices=CALLERID_FILTER_CHOICES, |
766
|
|
|
default='1') |
767
|
|
|
callerid_list = models.ForeignKey(CalleridPrefixList, |
768
|
|
|
verbose_name=_(u"CallerID prefix List"), |
769
|
|
|
blank=True, |
770
|
|
|
null=True) |
771
|
|
|
date_start = models.DateTimeField() |
772
|
|
|
date_end = models.DateTimeField() |
773
|
|
|
quality = models.IntegerField(_(u'quality'), |
774
|
|
|
blank=True, |
775
|
|
|
default='100', |
776
|
|
|
help_text=_(u"Order by quality.")) |
777
|
|
|
reliability = models.IntegerField(_(u'reliability'), |
778
|
|
|
blank=True, |
779
|
|
|
default='100', |
780
|
|
|
help_text=_(u"Order by reliability.")) |
781
|
|
|
cid = models.CharField(_(u'cid'), |
782
|
|
|
blank=True, |
783
|
|
|
default='', |
784
|
|
|
max_length=25, |
785
|
|
|
help_text=_(u"Regex to modify CallerID number.")) |
786
|
|
|
enabled = models.BooleanField(_(u"Enabled / Disabled"), |
787
|
|
|
default=True) |
788
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
789
|
|
|
auto_now_add=True) |
790
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
791
|
|
|
auto_now=True) |
792
|
|
|
|
793
|
|
|
class Meta: |
794
|
|
|
db_table = 'provider_tariff' |
795
|
|
|
ordering = ('enabled', |
796
|
|
|
'quality', |
797
|
|
|
'reliability') |
798
|
|
|
verbose_name = _(u'provider ratecard') |
799
|
|
|
verbose_name_plural = _(u'provider ratecards') |
800
|
|
|
|
801
|
|
|
def __unicode__(self): |
802
|
|
|
return u"%s" % self.name |
803
|
|
|
|
804
|
|
|
def rates(self): |
805
|
|
|
html = '<span><a href="/extranet/pyfreebill/providerrates/?provider_tariff__id__exact={0}" class="btn btn-inverse btn-mini">Rates <i class="icon-plus-sign"></i></a></span>' |
806
|
|
|
return format_html(html, (self.id)) |
807
|
|
|
rates.allow_tags = True |
808
|
|
|
rates.short_description = _(u'rates') |
809
|
|
|
|
810
|
|
|
|
811
|
|
|
class ProviderRates(models.Model): |
812
|
|
|
""" Provider Rates Model """ |
813
|
|
|
destination = models.CharField(_(u'destination'), |
814
|
|
|
blank=True, |
815
|
|
|
default='', |
816
|
|
|
null=True, |
817
|
|
|
max_length=128, |
818
|
|
|
db_index=True) |
819
|
|
|
digits = models.CharField(_(u'numeric prefix'), |
820
|
|
|
max_length=30, |
821
|
|
|
db_index=True) |
822
|
|
|
cost_rate = models.DecimalField(_(u'Cost rate'), |
823
|
|
|
max_digits=11, |
824
|
|
|
decimal_places=5) |
825
|
|
|
block_min_duration = models.IntegerField(_(u'block min duration'), |
826
|
|
|
default=1) |
827
|
|
|
init_block = models.DecimalField(_(u'Init block rate'), |
828
|
|
|
max_digits=11, |
829
|
|
|
decimal_places=5, |
830
|
|
|
default=0) |
831
|
|
|
provider_tariff = models.ForeignKey(ProviderTariff) |
832
|
|
|
date_start = models.DateTimeField() |
833
|
|
|
date_end = models.DateTimeField() |
834
|
|
|
enabled = models.BooleanField(_(u"Enabled / Disabled"), default=True) |
835
|
|
|
date_added = models.DateTimeField(_(u'date added'), auto_now_add=True) |
836
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), auto_now=True) |
837
|
|
|
|
838
|
|
|
class Meta: |
839
|
|
|
db_table = 'provider_rates' |
840
|
|
|
ordering = ('enabled', 'provider_tariff', 'digits') |
841
|
|
|
index_together = [ |
842
|
|
|
["provider_tariff", "digits", "enabled"], |
843
|
|
|
] |
844
|
|
|
unique_together = ("digits", "provider_tariff") |
845
|
|
|
verbose_name = _(u'provider rate') |
846
|
|
|
verbose_name_plural = _(u'provider rates') |
847
|
|
|
|
848
|
|
|
def __unicode__(self): |
849
|
|
|
return u"%s %s %s " % (self.digits, |
850
|
|
|
self.cost_rate, |
851
|
|
|
self.provider_tariff) |
852
|
|
|
|
853
|
|
|
def set_bar(self, value): |
854
|
|
|
self.bar = value |
855
|
|
|
simple_import_methods = ('set_bar',) |
856
|
|
|
|
857
|
|
|
|
858
|
|
|
# LCR |
859
|
|
|
|
860
|
|
|
|
861
|
|
|
class LCRGroup(models.Model): |
862
|
|
|
""" LCR group model """ |
863
|
|
|
name = models.CharField(_(u"name"), |
864
|
|
|
max_length=128, |
865
|
|
|
unique=True) |
866
|
|
|
description = models.TextField(_(u'description'), |
867
|
|
|
blank=True) |
868
|
|
|
LCR_TYPE_CHOICES = ( |
869
|
|
|
('p', _(u"lower price")), |
870
|
|
|
('q', _(u"best quality")), |
871
|
|
|
('r', _(u"best reliability")), |
872
|
|
|
('l', _(u"load balance")), |
873
|
|
|
) |
874
|
|
|
lcrtype = models.CharField(_(u"lcr type"), |
875
|
|
|
max_length=10, |
876
|
|
|
choices=LCR_TYPE_CHOICES, |
877
|
|
|
default='p') |
878
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
879
|
|
|
auto_now_add=True) |
880
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
881
|
|
|
auto_now=True) |
882
|
|
|
|
883
|
|
|
class Meta: |
884
|
|
|
db_table = 'lcr_group' |
885
|
|
|
ordering = ('name',) |
886
|
|
|
verbose_name = _(u'LCR') |
887
|
|
|
verbose_name_plural = _(u'LCRs') |
888
|
|
|
|
889
|
|
|
def __unicode__(self): |
890
|
|
|
return u"%s %s " % (self.name, self.lcrtype) |
891
|
|
|
|
892
|
|
|
|
893
|
|
|
class LCRProviders(models.Model): |
894
|
|
|
""" LCR group model """ |
895
|
|
|
lcr = models.ForeignKey(LCRGroup, |
896
|
|
|
verbose_name=_(u"LCR")) |
897
|
|
|
provider_tariff = models.ForeignKey(ProviderTariff, |
898
|
|
|
verbose_name=_(u"Provider tariff")) |
899
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
900
|
|
|
auto_now_add=True) |
901
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
902
|
|
|
auto_now=True) |
903
|
|
|
|
904
|
|
|
class Meta: |
905
|
|
|
db_table = 'lcr_providers' |
906
|
|
|
verbose_name = _(u'LCR provider') |
907
|
|
|
verbose_name_plural = _(u'LCR providers') |
908
|
|
|
|
909
|
|
|
def __unicode__(self): |
910
|
|
|
return u"%s - %s " % (self.lcr, self.provider_tariff) |
911
|
|
|
|
912
|
|
|
def rates(self): |
913
|
|
|
html = '<span><a href="/extranet/pyfreebill/providerrates/?provider_tariff__id__exact={0}" class="btn btn-inverse btn-mini">Rates <i class="icon-plus-sign"></i></a></span>' |
914
|
|
|
return format_html(html, (self.provider_tariff)) |
915
|
|
|
rates.allow_tags = True |
916
|
|
|
rates.short_description = _(u'rates') |
917
|
|
|
|
918
|
|
|
|
919
|
|
|
# Ratecard |
920
|
|
|
|
921
|
|
|
|
922
|
|
|
class RateCard(models.Model): |
923
|
|
|
""" RateCard Model """ |
924
|
|
|
name = models.CharField(_(u'name'), |
925
|
|
|
max_length=128, |
926
|
|
|
unique=True) |
927
|
|
|
description = models.TextField(_(u'description'), |
928
|
|
|
blank=True) |
929
|
|
|
currency = models.ForeignKey(Currency, |
930
|
|
|
verbose_name=_(u"Currency")) |
931
|
|
|
lcrgroup = models.ForeignKey(LCRGroup, |
932
|
|
|
verbose_name=_(u"lcr")) |
933
|
|
|
CALLERID_FILTER_CHOICES = ( |
934
|
|
|
('1', _(u"No filter")), |
935
|
|
|
('2', _(u"Prefix authorized")), |
936
|
|
|
('3', _(u"Prefix prohibited")), |
937
|
|
|
) |
938
|
|
|
callerid_filter = models.CharField(_(u"CallerID Prefix filter"), |
939
|
|
|
max_length=2, |
940
|
|
|
choices=CALLERID_FILTER_CHOICES, |
941
|
|
|
default='1') |
942
|
|
|
callerid_list = models.ForeignKey(CalleridPrefixList, |
943
|
|
|
verbose_name=_(u"CallerID prefix List"), |
944
|
|
|
blank=True, |
945
|
|
|
null=True) |
946
|
|
|
enabled = models.BooleanField(_(u"Enabled / Disabled"), |
947
|
|
View Code Duplication |
default=True) |
|
|
|
|
948
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
949
|
|
|
auto_now_add=True) |
950
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
951
|
|
|
auto_now=True) |
952
|
|
|
|
953
|
|
|
class Meta: |
954
|
|
|
db_table = 'ratecard' |
955
|
|
|
ordering = ('name', 'enabled') |
956
|
|
|
verbose_name = _(u'Customer ratecard') |
957
|
|
|
verbose_name_plural = _(u'Customer ratecards') |
958
|
|
|
|
959
|
|
|
def __unicode__(self): |
960
|
|
|
return u"%s" % self.name |
961
|
|
|
|
962
|
|
|
def rates(self): |
963
|
|
|
html = '<span><a href="/extranet/pyfreebill/customerrates/?ratecard__id__exact={0}" class="btn btn-inverse btn-mini">Rates <i class="icon-plus-sign"></i></a></span>' |
964
|
|
|
return format_html(html, (self.id)) |
965
|
|
|
rates.allow_tags = True |
966
|
|
|
rates.short_description = _(u'Rates') |
967
|
|
|
|
968
|
|
|
def lcr(self): |
969
|
|
|
html = '<span><a href="/extranet/pyfreebill/lcrgroup/{0}/" class="btn btn-inverse btn-mini">LCR <i class="icon-plus-sign"></i></a></span>' |
970
|
|
|
return format_html(html, (self.lcrgroup.pk)) |
971
|
|
|
lcr.allow_tags = True |
972
|
|
|
lcr.short_description = _(u'lcr') |
973
|
|
|
|
974
|
|
|
|
975
|
|
|
class CustomerRates(models.Model): |
976
|
|
|
""" Customer Rates Model """ |
977
|
|
|
ratecard = models.ForeignKey(RateCard, |
978
|
|
|
verbose_name=_(u"ratecard")) |
979
|
|
|
destination = models.CharField(_(u'destination'), |
980
|
|
|
blank=True, |
981
|
|
|
default='', |
982
|
|
|
null=True, |
983
|
|
|
max_length=128, |
984
|
|
|
db_index=True) |
985
|
|
|
prefix = models.CharField(_(u'numeric prefix'), |
986
|
|
|
max_length=30, |
987
|
|
|
db_index=True) |
988
|
|
|
rate = models.DecimalField(_(u'sell rate'), |
989
|
|
|
max_digits=11, |
990
|
|
|
decimal_places=5, |
991
|
|
|
help_text=_(u"to block the prefix, put -1")) |
992
|
|
|
block_min_duration = models.IntegerField(_(u'Increment'), |
993
|
|
|
default=1) |
994
|
|
|
minimal_time = models.IntegerField(_(u'Minimal time'), |
995
|
|
|
default=1) |
996
|
|
|
init_block = models.DecimalField(_(u'Connection fee'), |
997
|
|
|
max_digits=11, |
998
|
|
|
decimal_places=5, |
999
|
|
|
default=0) |
1000
|
|
|
date_start = models.DateTimeField() |
1001
|
|
|
date_end = models.DateTimeField() |
1002
|
|
|
enabled = models.BooleanField(_(u"Enabled"), |
1003
|
|
|
default=True) |
1004
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1005
|
|
|
auto_now_add=True) |
1006
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1007
|
|
|
auto_now=True) |
1008
|
|
|
|
1009
|
|
|
class Meta: |
1010
|
|
|
db_table = 'customer_rates' |
1011
|
|
|
ordering = ('ratecard', 'prefix', 'enabled') |
1012
|
|
|
unique_together = ("ratecard", "prefix") |
1013
|
|
|
verbose_name = _(u'customer rate') |
1014
|
|
|
verbose_name_plural = _(u'customer rates') |
1015
|
|
|
|
1016
|
|
|
def __unicode__(self): |
1017
|
|
|
return u"%s" % self.ratecard |
1018
|
|
|
|
1019
|
|
|
|
1020
|
|
|
class CustomerRateCards(models.Model): |
1021
|
|
|
""" Customer rates Cards Model """ |
1022
|
|
|
company = models.ForeignKey(Company, |
1023
|
|
|
verbose_name=_(u"company")) |
1024
|
|
|
ratecard = models.ForeignKey(RateCard, |
1025
|
|
|
verbose_name=_(u"ratecard")) |
1026
|
|
|
description = models.TextField(_(u'description'), |
1027
|
|
|
blank=True) |
1028
|
|
|
tech_prefix = models.CharField(_(u"technical prefix"), |
1029
|
|
|
blank=True, |
1030
|
|
|
default='', |
1031
|
|
|
null=True, |
1032
|
|
|
max_length=7) |
1033
|
|
|
DEFAULT_PRIORITY_CHOICES = ( |
1034
|
|
|
(1, _(u'1')), |
1035
|
|
|
(2, _(u'2')), |
1036
|
|
|
(3, _(u'3')), |
1037
|
|
|
) |
1038
|
|
|
priority = models.IntegerField(_(u'priority'), |
1039
|
|
|
choices=DEFAULT_PRIORITY_CHOICES, |
1040
|
|
|
help_text=_(u"""Priority order, 1 is the |
1041
|
|
|
higher priority and 3 the |
1042
|
|
|
lower one. Correct values |
1043
|
|
|
are : 1, 2 or 3 !.""")) |
1044
|
|
|
discount = models.DecimalField(_(u'discount'), |
1045
|
|
|
max_digits=3, |
1046
|
|
|
decimal_places=2, |
1047
|
|
|
default=0, |
1048
|
|
|
help_text=_(u"""ratecard discount. For |
1049
|
|
|
10% discount, enter 10 !""")) |
1050
|
|
|
allow_negative_margin = models.BooleanField(_(u"""Allow calls with |
1051
|
|
|
negative margin"""), |
1052
|
|
|
default=False) |
1053
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1054
|
|
|
auto_now_add=True) |
1055
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1056
|
|
|
auto_now=True) |
1057
|
|
|
|
1058
|
|
|
class Meta: |
1059
|
|
|
db_table = 'customer_ratecards' |
1060
|
|
|
ordering = ('company', 'priority', 'ratecard') |
1061
|
|
|
verbose_name = _(u'Customer Ratecard Allocation') |
1062
|
|
|
verbose_name_plural = _(u'Customer ratecard Allocations') |
1063
|
|
|
|
1064
|
|
|
def __unicode__(self): |
1065
|
|
|
return u"%s - Priority: %s Desc: %s" % (self.ratecard, |
1066
|
|
|
self.priority, |
1067
|
|
|
self.description) |
1068
|
|
|
|
1069
|
|
|
|
1070
|
|
|
# NORMALIZATION |
1071
|
|
|
|
1072
|
|
|
|
1073
|
|
|
class DestinationNumberRules(models.Model): |
1074
|
|
|
""" Destination Number Normalization Rules """ |
1075
|
|
|
prefix = models.CharField(_(u'numeric prefix'), |
1076
|
|
|
max_length=30) |
1077
|
|
|
description = models.TextField(_(u'description'), |
1078
|
|
|
blank=True) |
1079
|
|
|
format_num = models.CharField(_(u"Rule format"), |
1080
|
|
|
max_length=150, |
1081
|
|
|
help_text=_(u"""example for Tunisia : |
1082
|
|
|
^216[%d][%d][%d][%d][%d][%d][%d][%d] |
1083
|
|
|
$""")) |
1084
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1085
|
|
|
auto_now_add=True) |
1086
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1087
|
|
|
auto_now=True) |
1088
|
|
|
|
1089
|
|
|
class Meta: |
1090
|
|
|
db_table = 'destination_norm_rules' |
1091
|
|
|
ordering = ('prefix',) |
1092
|
|
|
verbose_name = _(u'Destination Number Normalization Rule') |
1093
|
|
|
verbose_name_plural = _(u'Destination Number Normalization Rules') |
1094
|
|
|
|
1095
|
|
|
def __unicode__(self): |
1096
|
|
|
return u"%s -> %s " % (self.prefix, self.format_num) |
1097
|
|
|
|
1098
|
|
|
|
1099
|
|
|
class CustomerNormalizationRules(models.Model): |
1100
|
|
|
""" Customer Normalization Rules """ |
1101
|
|
|
company = models.ForeignKey(Company, |
1102
|
|
|
verbose_name=_(u"customer")) |
1103
|
|
|
prefix = models.CharField(_(u'rule title'), |
1104
|
|
|
max_length=30) |
1105
|
|
|
description = models.TextField(_(u'description'), |
1106
|
|
|
blank=True) |
1107
|
|
|
remove_prefix = models.CharField(_(u"remove prefix"), |
1108
|
|
|
blank=True, |
1109
|
|
|
default='', |
1110
|
|
|
max_length=15) |
1111
|
|
|
add_prefix = models.CharField(_(u"add prefix"), |
1112
|
|
|
blank=True, |
1113
|
|
|
default='', |
1114
|
|
|
max_length=15) |
1115
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1116
|
|
|
auto_now_add=True) |
1117
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1118
|
|
|
auto_now=True) |
1119
|
|
|
|
1120
|
|
|
class Meta: |
1121
|
|
|
db_table = 'customer_norm_rules' |
1122
|
|
|
ordering = ('company', 'prefix') |
1123
|
|
|
verbose_name = _(u'Customer Normalization Rule') |
1124
|
|
|
verbose_name_plural = _(u'Customer Normalization Rules') |
1125
|
|
|
|
1126
|
|
|
def __unicode__(self): |
1127
|
|
|
return u"%s -> %s -%s +%s" % (self.company, |
1128
|
|
|
self.prefix, |
1129
|
|
|
self.remove_prefix, |
1130
|
|
|
self.add_prefix) |
1131
|
|
|
|
1132
|
|
|
|
1133
|
|
|
class CarrierNormalizationRules(models.Model): |
1134
|
|
|
""" Carrier Normalization Rules """ |
1135
|
|
|
company = models.ForeignKey(Company, |
1136
|
|
|
verbose_name=_(u"provider")) |
1137
|
|
|
prefix = models.CharField(_(u'rule title'), |
1138
|
|
|
max_length=30) |
1139
|
|
|
description = models.TextField(_(u'description'), |
1140
|
|
|
blank=True) |
1141
|
|
|
remove_prefix = models.CharField(_(u"remove prefix"), |
1142
|
|
|
blank=True, |
1143
|
|
|
default='', |
1144
|
|
|
max_length=15) |
1145
|
|
|
add_prefix = models.CharField(_(u"add prefix"), |
1146
|
|
|
blank=True, |
1147
|
|
|
default='', |
1148
|
|
|
max_length=15) |
1149
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1150
|
|
|
auto_now_add=True) |
1151
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1152
|
|
|
auto_now=True) |
1153
|
|
|
|
1154
|
|
|
class Meta: |
1155
|
|
|
db_table = 'carrier_norm_rules' |
1156
|
|
|
ordering = ('company', 'prefix') |
1157
|
|
|
verbose_name = _(u'Provider Normalization Rule') |
1158
|
|
|
verbose_name_plural = _(u'Provider Normalization Rules') |
1159
|
|
|
|
1160
|
|
|
def __unicode__(self): |
1161
|
|
|
return u"%s -> %s -%s +%s" % (self.company, |
1162
|
|
|
self.prefix, |
1163
|
|
|
self.remove_prefix, |
1164
|
|
|
self.add_prefix) |
1165
|
|
|
|
1166
|
|
|
|
1167
|
|
|
class CustomerCIDNormalizationRules(models.Model): |
1168
|
|
|
""" Customer Caller ID Number Normalization Rules """ |
1169
|
|
|
company = models.ForeignKey(Company, |
1170
|
|
|
verbose_name=_(u"customer")) |
1171
|
|
|
prefix = models.CharField(_(u'rule title'), |
1172
|
|
|
max_length=30) |
1173
|
|
|
description = models.TextField(_(u'description'), |
1174
|
|
|
blank=True) |
1175
|
|
|
remove_prefix = models.CharField(_(u"remove prefix"), |
1176
|
|
|
blank=True, |
1177
|
|
|
default='', |
1178
|
|
|
max_length=15) |
1179
|
|
|
add_prefix = models.CharField(_(u"add prefix"), |
1180
|
|
|
blank=True, |
1181
|
|
|
default='', |
1182
|
|
|
max_length=15) |
1183
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1184
|
|
|
auto_now_add=True) |
1185
|
|
View Code Duplication |
date_modified = models.DateTimeField(_(u'date modified'), |
|
|
|
|
1186
|
|
|
auto_now=True) |
1187
|
|
|
|
1188
|
|
|
class Meta: |
1189
|
|
|
db_table = 'customer_cid_norm_rules' |
1190
|
|
|
ordering = ('company', ) |
1191
|
|
|
verbose_name = _(u'Customer CallerID Normalization Rule') |
1192
|
|
|
verbose_name_plural = _(u'Customer CallerID Normalization Rules') |
1193
|
|
|
|
1194
|
|
|
def __unicode__(self): |
1195
|
|
|
return u"%s -> -%s +%s" % (self.company, |
1196
|
|
|
self.remove_prefix, |
1197
|
|
|
self.add_prefix) |
1198
|
|
|
|
1199
|
|
|
|
1200
|
|
|
class CarrierCIDNormalizationRules(models.Model): |
1201
|
|
|
""" Carrier Caller ID Number Normalization Rules """ |
1202
|
|
|
company = models.ForeignKey(Company, |
1203
|
|
|
verbose_name=_(u"provider")) |
1204
|
|
|
prefix = models.CharField(_(u'rule title'), |
1205
|
|
|
max_length=30) |
1206
|
|
|
description = models.TextField(_(u'description'), |
1207
|
|
|
blank=True) |
1208
|
|
|
remove_prefix = models.CharField(_(u"remove prefix"), |
1209
|
|
|
blank=True, |
1210
|
|
|
default='', |
1211
|
|
|
max_length=15) |
1212
|
|
|
add_prefix = models.CharField(_(u"add prefix"), |
1213
|
|
|
blank=True, |
1214
|
|
|
default='', |
1215
|
|
|
max_length=15) |
1216
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1217
|
|
|
auto_now_add=True) |
1218
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1219
|
|
|
auto_now=True) |
1220
|
|
|
|
1221
|
|
|
class Meta: |
1222
|
|
|
db_table = 'carrier_cid_norm_rules' |
1223
|
|
|
ordering = ('company', ) |
1224
|
|
|
verbose_name = _(u'Provider CallerID Normalization Rule') |
1225
|
|
|
verbose_name_plural = _(u'Provider CallerID Normalization Rules') |
1226
|
|
|
|
1227
|
|
|
def __unicode__(self): |
1228
|
|
|
return u"%s -> -%s +%s" % (self.company, |
1229
|
|
|
self.remove_prefix, |
1230
|
|
|
self.add_prefix) |
1231
|
|
|
|
1232
|
|
|
# ACL |
1233
|
|
|
|
1234
|
|
|
|
1235
|
|
|
class AclLists(models.Model): |
1236
|
|
|
""" ACL list model """ |
1237
|
|
|
acl_name = models.CharField(_(u'name'), |
1238
|
|
|
max_length=128) |
1239
|
|
|
DEFAULT_POLICY_CHOICES = ( |
1240
|
|
|
('deny', _(u'deny')), |
1241
|
|
|
('allow', _(u'allow')), |
1242
|
|
|
) |
1243
|
|
|
default_policy = models.CharField(_(u'default policy'), |
1244
|
|
|
max_length=10, |
1245
|
|
|
choices=DEFAULT_POLICY_CHOICES, |
1246
|
|
|
default='deny') |
1247
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1248
|
|
|
auto_now_add=True) |
1249
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1250
|
|
|
auto_now=True) |
1251
|
|
|
|
1252
|
|
View Code Duplication |
class Meta: |
|
|
|
|
1253
|
|
|
db_table = 'acl_lists' |
1254
|
|
|
ordering = ('acl_name',) |
1255
|
|
|
verbose_name = _(u'ACL list') |
1256
|
|
|
verbose_name_plural = _(u'ACL lists') |
1257
|
|
|
|
1258
|
|
|
def __unicode__(self): |
1259
|
|
|
return u"%s" % self.acl_name |
1260
|
|
|
|
1261
|
|
|
|
1262
|
|
|
class AclNodes(models.Model): |
1263
|
|
|
""" ACL NODES model """ |
1264
|
|
|
company = models.ForeignKey(Company, |
1265
|
|
|
verbose_name=_(u"company")) |
1266
|
|
|
cidr = models.CharField(_(u"ip/cidr Address"), |
1267
|
|
|
max_length=100, |
1268
|
|
|
help_text=_(u"Customer IP or cidr address.")) |
1269
|
|
|
POLICY_CHOICES = ( |
1270
|
|
|
('deny', _('deny')), |
1271
|
|
|
('allow', _('allow')), |
1272
|
|
|
) |
1273
|
|
|
policy = models.CharField(_(u"policy"), |
1274
|
|
|
max_length=10, |
1275
|
|
|
choices=POLICY_CHOICES, |
1276
|
|
|
default='allow') |
1277
|
|
|
acllist = models.ForeignKey(AclLists, |
1278
|
|
|
verbose_name=_(u"acl list")) |
1279
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1280
|
|
|
auto_now_add=True) |
1281
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1282
|
|
|
auto_now=True) |
1283
|
|
|
|
1284
|
|
|
class Meta: |
1285
|
|
|
db_table = 'acl_nodes' |
1286
|
|
|
ordering = ('company', 'policy', 'cidr') |
1287
|
|
|
verbose_name = _(u'ACL node') |
1288
|
|
|
verbose_name_plural = _(u'ACL nodes') |
1289
|
|
|
|
1290
|
|
|
def __unicode__(self): |
1291
|
|
|
return u"%s %s" % (self.company, self.cidr) |
1292
|
|
|
|
1293
|
|
|
# VOIP SWITCH |
1294
|
|
|
|
1295
|
|
|
|
1296
|
|
View Code Duplication |
class VoipSwitch(models.Model): |
|
|
|
|
1297
|
|
|
""" VoipSwitch Profile """ |
1298
|
|
|
name = models.CharField(_(u"Switch name"), |
1299
|
|
|
max_length=50, |
1300
|
|
|
help_text=_(u"Switch name")) |
1301
|
|
|
ip = models.CharField(_(u"switch IP"), |
1302
|
|
|
max_length=100, |
1303
|
|
|
default="auto", |
1304
|
|
|
help_text=_(u"Switch IP.")) |
1305
|
|
|
esl_listen_ip = models.CharField(_(u"event socket switch IP"), |
1306
|
|
|
max_length=100, |
1307
|
|
|
default="127.0.0.1", |
1308
|
|
|
help_text=_(u"Event socket switch IP.")) |
1309
|
|
|
esl_listen_port = models.PositiveIntegerField(_(u"""event socket switch |
1310
|
|
|
port"""), |
1311
|
|
|
default="8021", |
1312
|
|
|
help_text=_(u"""Event socket |
1313
|
|
|
switch port.""")) |
1314
|
|
|
esl_password = models.CharField(_(u"event socket switch password"), |
1315
|
|
|
max_length=30, |
1316
|
|
|
default="ClueCon", |
1317
|
|
|
help_text=_(u"""Event socket switch |
1318
|
|
|
password.""")) |
1319
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1320
|
|
|
auto_now_add=True) |
1321
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1322
|
|
|
auto_now=True) |
1323
|
|
|
|
1324
|
|
|
class Meta: |
1325
|
|
|
db_table = 'voip_switch' |
1326
|
|
|
ordering = ('name', ) |
1327
|
|
|
verbose_name = _(u'VoIP Switch') |
1328
|
|
|
verbose_name_plural = _(u'VoIP Switches') |
1329
|
|
|
|
1330
|
|
|
def __unicode__(self): |
1331
|
|
|
return u"%s (:%s)" % (self.name, self.ip) |
1332
|
|
|
|
1333
|
|
|
# SOFIA |
1334
|
|
|
|
1335
|
|
|
|
1336
|
|
|
class SipProfile(models.Model): |
1337
|
|
|
""" Sofia Sip profile """ |
1338
|
|
|
name = models.CharField(_(u"SIP profile name"), |
1339
|
|
|
max_length=50, |
1340
|
|
|
unique=True, |
1341
|
|
|
help_text=_(u"""E.g.: the name you want ...""")) |
1342
|
|
|
user_agent = models.CharField(_(u"User agent name"), |
1343
|
|
|
max_length=50, |
1344
|
|
|
default="pyfreebilling", |
1345
|
|
|
help_text=_(u"""E.g.: the user agent |
1346
|
|
|
you want ... - take care |
1347
|
|
|
with certain characters |
1348
|
|
|
such as @ could cause others sip |
1349
|
|
|
proxies reject yours messages as |
1350
|
|
|
invalid ! """)) |
1351
|
|
|
ext_rtp_ip = models.CharField(_(u"external RTP IP"), |
1352
|
|
|
max_length=100, |
1353
|
|
|
default="auto", |
1354
|
|
|
help_text=_(u"""External/public IP |
1355
|
|
|
address to bind to for RTP.""")) |
1356
|
|
|
ext_sip_ip = models.CharField(_(u"external SIP IP"), |
1357
|
|
|
max_length=100, |
1358
|
|
|
default="auto", |
1359
|
|
|
help_text=_(u"""External/public IP |
1360
|
|
|
address to bind to for |
1361
|
|
|
SIP.""")) |
1362
|
|
|
rtp_ip = models.CharField(_(u"RTP IP"), |
1363
|
|
|
max_length=100, |
1364
|
|
|
default="auto", |
1365
|
|
|
help_text=_(u"""Internal IP address to bind |
1366
|
|
|
to for RTP.""")) |
1367
|
|
|
sip_ip = models.CharField(_(u"SIP IP"), |
1368
|
|
|
max_length=100, |
1369
|
|
|
default="auto", |
1370
|
|
|
help_text=_(u"""Internal IP address to bind |
1371
|
|
|
to for SIP.""")) |
1372
|
|
|
sip_port = models.PositiveIntegerField(_(u"SIP port"), |
1373
|
|
|
default=5060) |
1374
|
|
|
disable_transcoding = models.BooleanField(_(u"disable transcoding"), |
1375
|
|
|
default=True, |
1376
|
|
|
help_text=_(u"""If true, you |
1377
|
|
|
can not use |
1378
|
|
|
transcoding.""")) |
1379
|
|
|
accept_blind_reg = models.BooleanField(_(u"accept blind registration"), |
1380
|
|
|
default=False, |
1381
|
|
|
help_text=_(u"""If true, anyone can |
1382
|
|
|
register to the server |
1383
|
|
|
and will not be |
1384
|
|
|
challenged for |
1385
|
|
|
username/password |
1386
|
|
|
information.""")) |
1387
|
|
|
disable_register = models.BooleanField(_(u"disable register"), |
1388
|
|
|
default=True, |
1389
|
|
|
help_text=_(u"""disable register |
1390
|
|
|
which may be undesirable |
1391
|
|
|
in a public switch """)) |
1392
|
|
|
apply_inbound_acl = models.BooleanField(_(u"Apply an inbound ACL"), |
1393
|
|
|
default=True, |
1394
|
|
|
help_text=_(u"""If true, FS will |
1395
|
|
|
apply the default acl |
1396
|
|
|
list : domains """)) |
1397
|
|
|
auth_calls = models.BooleanField(_(u"authenticate calls"), |
1398
|
|
|
default=True, |
1399
|
|
|
help_text=_(u"""If true, FreeeSWITCH will |
1400
|
|
|
authorize all calls on this |
1401
|
|
|
profile, i.e. challenge the |
1402
|
|
|
other side for |
1403
|
|
|
username/password information. |
1404
|
|
|
""")) |
1405
|
|
|
log_auth_failures = models.BooleanField(_(u"log auth failures"), |
1406
|
|
|
default=False, |
1407
|
|
|
help_text=_(u"""It true, log |
1408
|
|
|
authentication failures. |
1409
|
|
|
Required for Fail2ban. |
1410
|
|
|
""")) |
1411
|
|
|
MULTIPLE_CODECS_CHOICES = ( |
1412
|
|
|
("PCMA,PCMU,G729", _(u"PCMA,PCMU,G729")), |
1413
|
|
|
("PCMU,PCMA,G729", _(u"PCMU,PCMA,G729")), |
1414
|
|
|
("G729,PCMA,PCMU", _(u"G729,PCMA,PCMU")), |
1415
|
|
|
("G729,PCMU,PCMA", _(u"G729,PCMU,PCMA")), |
1416
|
|
|
("PCMA,G729", _(u"PCMA,G729")), |
1417
|
|
|
("PCMU,G729", _(u"PCMU,G729")), |
1418
|
|
|
("G729,PCMA", _(u"G729,PCMA")), |
1419
|
|
|
("G729,PCMU", _(u"G729,PCMU")), |
1420
|
|
|
("PCMA,PCMU", _(u"PCMA,PCMU")), |
1421
|
|
|
("PCMU,PCMA", _(u"PCMU,PCMA")), |
1422
|
|
|
("G722,PCMA,PCMU", _(u"G722,PCMA,PCMU")), |
1423
|
|
|
("G722,PCMU,PCMA", _(u"G722,PCMU,PCMA")), |
1424
|
|
|
("G722", _(u"G722")), |
1425
|
|
|
("G729", _(u"G729")), |
1426
|
|
|
("PCMU", _(u"PCMU")), |
1427
|
|
|
("PCMA", _(u"PCMA")), |
1428
|
|
|
("ALL", _(u"ALL")), |
1429
|
|
|
) |
1430
|
|
|
inbound_codec_prefs = models.CharField(_(u"inbound codec prefs"), |
1431
|
|
|
max_length=100, |
1432
|
|
|
choices=MULTIPLE_CODECS_CHOICES, |
1433
|
|
|
default="G729,PCMU,PCMA", |
1434
|
|
|
help_text=_(u"""Define allowed |
1435
|
|
|
preferred codecs for |
1436
|
|
|
inbound calls.""")) |
1437
|
|
|
outbound_codec_prefs = models.CharField(_(u"outbound codec prefs"), |
1438
|
|
|
max_length=100, |
1439
|
|
|
choices=MULTIPLE_CODECS_CHOICES, |
1440
|
|
|
default="G729,PCMU,PCMA", |
1441
|
|
|
help_text=_(u"""Define allowed |
1442
|
|
|
preferred codecs for |
1443
|
|
|
outbound calls.""")) |
1444
|
|
|
aggressive_nat_detection = models.BooleanField(_(u"""Agressive NAT |
1445
|
|
|
detection"""), |
1446
|
|
|
default=False, |
1447
|
|
|
help_text=_(u"""This will |
1448
|
|
|
enable NAT mode |
1449
|
|
|
if the network |
1450
|
|
|
IP/port from |
1451
|
|
|
which therequest |
1452
|
|
|
was received |
1453
|
|
|
differs from the |
1454
|
|
|
IP/Port |
1455
|
|
|
combination in |
1456
|
|
|
the SIP Via: |
1457
|
|
|
header, or if |
1458
|
|
|
the Via: header |
1459
|
|
|
contains the |
1460
|
|
|
received |
1461
|
|
|
parameter""")) |
1462
|
|
|
NDLB_rec_in_nat_reg_c = models.BooleanField(_(u"""NDLB received |
1463
|
|
|
in nat reg contact"""), |
1464
|
|
|
default=False, |
1465
|
|
|
help_text=_(u"""add a;received= |
1466
|
|
|
"ip:port" |
1467
|
|
|
to the contact when |
1468
|
|
|
replying to |
1469
|
|
|
register |
1470
|
|
|
for nat handling |
1471
|
|
|
""")) |
1472
|
|
|
NDLB_FP_CHOICES = ( |
1473
|
|
|
("true", _(u"true")), |
1474
|
|
|
("safe", _(u"safe")), |
1475
|
|
|
) |
1476
|
|
|
NDLB_force_rport = models.CharField(_(u"""NDLB Force rport"""), |
1477
|
|
|
max_length=10, |
1478
|
|
|
choices=NDLB_FP_CHOICES, |
1479
|
|
|
null=True, |
1480
|
|
|
blank=True, |
1481
|
|
|
default="Null", |
1482
|
|
|
help_text=_(u"""This will force |
1483
|
|
|
FreeSWITCH to send |
1484
|
|
|
SIP responses to the |
1485
|
|
|
network port from |
1486
|
|
|
which they were received. |
1487
|
|
|
Use at your own risk!""")) |
1488
|
|
|
NDLB_broken_auth_hash = models.BooleanField(_(u"""NDLB broken auth hash |
1489
|
|
|
"""), |
1490
|
|
|
default=False, |
1491
|
|
|
help_text=_(u"""Used for when |
1492
|
|
|
phones respond to a |
1493
|
|
|
challenged ACK |
1494
|
|
|
with method INVITE |
1495
|
|
|
in the hash""")) |
1496
|
|
|
enable_timer = models.BooleanField(_(u"""Enable timer"""), |
1497
|
|
|
default=False, |
1498
|
|
|
help_text=_(u"""This enables or disables |
1499
|
|
|
support for RFC 4028 SIP |
1500
|
|
|
Session Timers""")) |
1501
|
|
|
session_timeout = models.PositiveIntegerField(_(u"""Session timeout"""), |
1502
|
|
|
default=1800, |
1503
|
|
|
help_text=_(u"""session |
1504
|
|
|
timers for all |
1505
|
|
|
call to expire |
1506
|
|
|
after the |
1507
|
|
|
specified seconds |
1508
|
|
|
Then it will send |
1509
|
|
|
another invite |
1510
|
|
|
--re-invite. If |
1511
|
|
|
not specified |
1512
|
|
|
defaults to 30 |
1513
|
|
|
minutes. Some |
1514
|
|
|
gateways may |
1515
|
|
|
reject values |
1516
|
|
|
less than 30 |
1517
|
|
|
minutes. This |
1518
|
|
|
values refers to |
1519
|
|
|
Session-Expires |
1520
|
|
|
in RFC 4028 -The |
1521
|
|
|
time at which |
1522
|
|
|
an element will |
1523
|
|
|
consider the |
1524
|
|
|
session timed |
1525
|
|
|
out, if no |
1526
|
|
|
successful |
1527
|
|
|
session refresh |
1528
|
|
|
transaction |
1529
|
|
|
occurs |
1530
|
|
|
beforehand- |
1531
|
|
|
""")) |
1532
|
|
|
rtp_rewrite_timestamps = models.BooleanField(_(u"""RTP rewrite timestamps"""), |
1533
|
|
|
default=False, |
1534
|
|
|
help_text=_(u"""If you don't want to pass |
1535
|
|
|
through timestampes from 1 RTP call |
1536
|
|
|
to another""")) |
1537
|
|
|
pass_rfc2833 = models.BooleanField(_(u"""pass rfc2833"""), |
1538
|
|
|
default=False, |
1539
|
|
|
help_text=_(u"""pass rfc2833""")) |
1540
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1541
|
|
|
auto_now_add=True) |
1542
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1543
|
|
|
auto_now=True) |
1544
|
|
|
|
1545
|
|
|
class Meta: |
1546
|
|
|
db_table = 'sip_profile' |
1547
|
|
|
ordering = ('name', ) |
1548
|
|
|
unique_together = ("sip_ip", "sip_port") |
1549
|
|
|
verbose_name = _(u'SIP profile') |
1550
|
|
|
verbose_name_plural = _(u'SIP profiles') |
1551
|
|
|
|
1552
|
|
|
def __unicode__(self): |
1553
|
|
|
return u"%s (%s:%s)" % (self.name, self.sip_ip, self.sip_port) |
1554
|
|
|
|
1555
|
|
|
def get_gateways(self): |
1556
|
|
|
"""Get all gateways in the system assigned to this sip profile.""" |
1557
|
|
|
retval = [] |
1558
|
|
|
accounts = Company.objects.filter(supplier_enabled=True) |
1559
|
|
|
for account in accounts: |
1560
|
|
|
for gateway in account.sofiagateway_set.all(): |
1561
|
|
|
if gateway.sip_profile.id == self.id: |
1562
|
|
|
retval.append(gateway) |
1563
|
|
|
return retval |
1564
|
|
|
|
1565
|
|
|
|
1566
|
|
|
class SofiaGateway(models.Model): |
1567
|
|
|
name = models.CharField(_(u"name"), |
1568
|
|
|
max_length=100, |
1569
|
|
|
unique=True) |
1570
|
|
|
sip_profile = models.ForeignKey('SipProfile', |
1571
|
|
|
verbose_name=_(u"SIP profile"), |
1572
|
|
|
help_text=_(u"""Which Sip Profile |
1573
|
|
|
communication with this gateway will |
1574
|
|
|
take place on.""")) |
1575
|
|
|
company = models.ForeignKey(Company, |
1576
|
|
|
verbose_name=_(u"Provider"), |
1577
|
|
|
db_index=True) |
1578
|
|
|
channels = models.PositiveIntegerField(_(u"channels number"), |
1579
|
|
|
default=1, |
1580
|
|
|
help_text=_(u"""maximum simultaneous |
1581
|
|
|
calls allowed for this gateway. |
1582
|
|
|
""")) |
1583
|
|
|
enabled = models.BooleanField(_(u"Enabled"), |
1584
|
|
|
default=True) |
1585
|
|
|
prefix = models.CharField(_(u'prefix'), |
1586
|
|
|
blank=True, |
1587
|
|
|
default='', |
1588
|
|
|
max_length=15) |
1589
|
|
|
suffix = models.CharField(_(u'suffix'), |
1590
|
|
|
blank=True, |
1591
|
|
|
default='', |
1592
|
|
|
max_length=15) |
1593
|
|
|
MULTIPLE_CODECS_CHOICES = ( |
1594
|
|
|
("PCMA,PCMU,G729", _(u"PCMA,PCMU,G729")), |
1595
|
|
|
("PCMU,PCMA,G729", _(u"PCMU,PCMA,G729")), |
1596
|
|
|
("G729,PCMA,PCMU", _(u"G729,PCMA,PCMU")), |
1597
|
|
|
("G729,PCMU,PCMA", _(u"G729,PCMU,PCMA")), |
1598
|
|
|
("PCMA,G729", _(u"PCMA,G729")), |
1599
|
|
|
("PCMU,G729", _(u"PCMU,G729")), |
1600
|
|
|
("G729,PCMA", _(u"G729,PCMA")), |
1601
|
|
|
("G729,PCMU", _(u"G729,PCMU")), |
1602
|
|
|
("PCMA,PCMU", _(u"PCMA,PCMU")), |
1603
|
|
|
("PCMU,PCMA", _(u"PCMU,PCMA")), |
1604
|
|
|
("G722,PCMA,PCMU", _(u"G722,PCMA,PCMU")), |
1605
|
|
|
("G722,PCMU,PCMA", _(u"G722,PCMU,PCMA")), |
1606
|
|
|
("G722", _(u"G722")), |
1607
|
|
|
("G729", _(u"G729")), |
1608
|
|
|
("PCMU", _(u"PCMU")), |
1609
|
|
|
("PCMA", _(u"PCMA")), |
1610
|
|
|
("ALL", _(u"ALL")), |
1611
|
|
|
) |
1612
|
|
|
codec = models.CharField(_(u"Codecs"), |
1613
|
|
|
max_length=30, |
1614
|
|
|
default="ALL", |
1615
|
|
|
choices=MULTIPLE_CODECS_CHOICES, |
1616
|
|
|
help_text=_(u"""Codecs allowed - beware about |
1617
|
|
|
order, 1st has high priority """)) |
1618
|
|
|
username = models.CharField(_(u"username"), |
1619
|
|
|
blank=True, |
1620
|
|
|
default='', |
1621
|
|
|
max_length=35) |
1622
|
|
|
password = models.CharField(_(u"password"), |
1623
|
|
|
blank=True, |
1624
|
|
|
default='', |
1625
|
|
|
max_length=35) |
1626
|
|
|
register = models.BooleanField(_(u"register"), |
1627
|
|
|
default=False) |
1628
|
|
|
proxy = models.CharField(_(u"proxy"), |
1629
|
|
|
max_length=48, |
1630
|
|
|
default="", |
1631
|
|
|
help_text=_(u"IP if register is False.")) |
1632
|
|
|
extension = models.CharField(_(u"extension number"), |
1633
|
|
|
max_length=50, |
1634
|
|
|
blank=True, |
1635
|
|
|
default="", |
1636
|
|
|
help_text=_(u"""Extension for inbound calls. |
1637
|
|
|
Same as username, if blank.""")) |
1638
|
|
|
realm = models.CharField(_(u"realm"), |
1639
|
|
|
max_length=50, |
1640
|
|
|
blank=True, |
1641
|
|
|
default="", |
1642
|
|
|
help_text=_(u"""Authentication realm. Same as |
1643
|
|
|
gateway name, if blank.""")) |
1644
|
|
|
from_domain = models.CharField(_(u"from domain"), |
1645
|
|
|
max_length=50, |
1646
|
|
|
blank=True, |
1647
|
|
|
default="", |
1648
|
|
|
help_text=_(u"""Domain to use in from field. |
1649
|
|
|
Same as realm if blank.""")) |
1650
|
|
|
expire_seconds = models.PositiveIntegerField(_(u"expire seconds"), |
1651
|
|
|
default=3600, |
1652
|
|
|
null=True) |
1653
|
|
|
retry_seconds = models.PositiveIntegerField(_(u"retry seconds"), |
1654
|
|
|
default=30, |
1655
|
|
|
null=True, |
1656
|
|
|
help_text=_(u"""How many |
1657
|
|
|
seconds before a retry when |
1658
|
|
|
a failure or timeout occurs |
1659
|
|
|
""")) |
1660
|
|
|
caller_id_in_from = models.BooleanField(_(u"caller ID in From field"), |
1661
|
|
|
default=True, |
1662
|
|
|
help_text=_(u"""Use the callerid of |
1663
|
|
|
an inbound call in the from |
1664
|
|
|
field on outbound calls via |
1665
|
|
|
this gateway.""")) |
1666
|
|
|
SIP_CID_TYPE_CHOICES = ( |
1667
|
|
|
('none', _(u'none')), |
1668
|
|
|
('default', _(u'default')), |
1669
|
|
|
('pid', _(u'pid')), |
1670
|
|
|
('rpid', _(u'rpid')), |
1671
|
|
|
) |
1672
|
|
|
sip_cid_type = models.CharField(_(u'SIP CID type'), |
1673
|
|
|
max_length=10, |
1674
|
|
|
choices=SIP_CID_TYPE_CHOICES, |
1675
|
|
|
default='rpid', |
1676
|
|
|
help_text=_(u"""Modify callerID in SDP |
1677
|
|
|
Headers.""")) |
1678
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1679
|
|
|
auto_now_add=True) |
1680
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1681
|
|
|
auto_now=True) |
1682
|
|
|
|
1683
|
|
|
class Meta: |
1684
|
|
|
db_table = 'sofia_gateway' |
1685
|
|
|
ordering = ('company', 'name') |
1686
|
|
|
verbose_name = _(u"Sofia gateway") |
1687
|
|
|
verbose_name_plural = _(u"Sofia gateways") |
1688
|
|
|
|
1689
|
|
|
def __unicode__(self): |
1690
|
|
|
return u"%s" % self.name |
1691
|
|
|
|
1692
|
|
|
# Hangup Cause |
1693
|
|
|
|
1694
|
|
|
|
1695
|
|
View Code Duplication |
class HangupCause(models.Model): |
|
|
|
|
1696
|
|
|
""" Hangup Cause Model """ |
1697
|
|
|
code = models.PositiveIntegerField(_(u"Hangup code"), |
1698
|
|
|
unique=True, |
1699
|
|
|
help_text=_(u"ITU-T Q.850 Code.")) |
1700
|
|
|
enumeration = models.CharField(_(u"enumeration"), |
1701
|
|
|
max_length=100, |
1702
|
|
|
null=True, |
1703
|
|
|
blank=True, |
1704
|
|
|
help_text=_(u"enumeration.")) |
1705
|
|
|
cause = models.CharField(_(u"cause"), |
1706
|
|
|
max_length=100, |
1707
|
|
|
null=True, |
1708
|
|
|
blank=True, |
1709
|
|
|
help_text=_(u"Cause.")) |
1710
|
|
|
description = models.TextField(_(u'description'), |
1711
|
|
|
blank=True) |
1712
|
|
|
date_added = models.DateTimeField(_(u'date added'), |
1713
|
|
|
auto_now_add=True) |
1714
|
|
|
date_modified = models.DateTimeField(_(u'date modified'), |
1715
|
|
|
auto_now=True) |
1716
|
|
|
|
1717
|
|
|
class Meta: |
1718
|
|
|
db_table = 'hangup_cause' |
1719
|
|
|
ordering = ('code',) |
1720
|
|
|
verbose_name = _(u"hangupcause") |
1721
|
|
|
verbose_name_plural = _(u"hangupcauses") |
1722
|
|
|
|
1723
|
|
|
def __unicode__(self): |
1724
|
|
|
return u"[%s] %s" % (self.code, self.enumeration) |
1725
|
|
|
|
1726
|
|
|
# CDR |
1727
|
|
|
|
1728
|
|
|
|
1729
|
|
|
class CDR(models.Model): |
1730
|
|
|
""" CDR Model """ |
1731
|
|
|
customer = models.ForeignKey(Company, verbose_name=_(u"customer"), null=True, related_name="customer_related") |
1732
|
|
|
customer_ip = models.CharField(_(u"customer IP address"), max_length=100, null=True, help_text=_(u"Customer IP address.")) |
1733
|
|
|
uuid = models.CharField(_(u"UUID"), max_length=100, null=True) |
1734
|
|
|
bleg_uuid = models.CharField(_(u"b leg UUID"), null=True, default="", max_length=100) |
1735
|
|
|
caller_id_number = models.CharField(_(u"caller ID num"), max_length=100, null=True) |
1736
|
|
|
destination_number = models.CharField(_(u"Dest. number"), max_length=100, null=True) |
1737
|
|
|
chan_name = models.CharField(_(u"channel name"), max_length=100, null=True) |
1738
|
|
|
start_stamp = models.DateTimeField(_(u"start time"), null=True, db_index=True) |
1739
|
|
|
answered_stamp = models.DateTimeField(_(u"answered time"), null=True) |
1740
|
|
|
end_stamp = models.DateTimeField(_(u"hangup time"), null=True) |
1741
|
|
|
duration = models.IntegerField(_(u"global duration"), null=True) |
1742
|
|
|
effectiv_duration = models.IntegerField(_(u"total duration"), null=True, help_text=_(u"Global call duration since call has been received by the switch in ms.")) |
1743
|
|
|
effective_duration = models.IntegerField(_(u"effective duration"), null=True, help_text=_(u"real call duration in s.")) |
1744
|
|
|
billsec = models.IntegerField(_(u"billed duration"), null=True, help_text=_(u"billed call duration in s.")) |
1745
|
|
|
read_codec = models.CharField(_(u"read codec"), max_length=20, null=True) |
1746
|
|
|
write_codec = models.CharField(_(u"write codec"), max_length=20, null=True) |
1747
|
|
View Code Duplication |
hangup_cause = models.CharField(_(u"hangup cause"), max_length=50, null=True, db_index=True) |
|
|
|
|
1748
|
|
|
hangup_cause_q850 = models.IntegerField(_(u"q.850"), null=True) |
1749
|
|
|
gateway = models.ForeignKey(SofiaGateway, verbose_name=_(u"gateway"), null=True) |
1750
|
|
|
cost_rate = models.DecimalField(_(u'buy rate'), max_digits=11, decimal_places=5, default="0", null=True) |
1751
|
|
|
total_sell = models.DecimalField(_(u'total sell'), max_digits=11, decimal_places=5, default="0", null=True) |
1752
|
|
|
total_cost = models.DecimalField(_(u'total cost'), max_digits=11, decimal_places=5, default="0", null=True) |
1753
|
|
|
prefix = models.CharField(_(u'Prefix'), max_length=30, null=True) |
1754
|
|
|
country = models.CharField(_(u'Country'), max_length=100, null=True) |
1755
|
|
|
rate = models.DecimalField(_(u'sell rate'), max_digits=11, decimal_places=5, null=True) |
1756
|
|
|
init_block = models.DecimalField(_(u'Connection fee'), max_digits=11, decimal_places=5, null=True) |
1757
|
|
|
block_min_duration = models.IntegerField(_(u'increment'), null=True) |
1758
|
|
|
lcr_carrier_id = models.ForeignKey(Company, verbose_name=_(u"provider"), null=True, related_name="carrier_related") |
1759
|
|
|
ratecard_id = models.ForeignKey(RateCard, null=True, verbose_name=_(u"ratecard")) |
1760
|
|
|
lcr_group_id = models.ForeignKey(LCRGroup, null=True, verbose_name=_(u"lcr group")) |
1761
|
|
|
sip_user_agent = models.CharField(_(u'sip user agent'), null=True, max_length=100) |
1762
|
|
|
sip_rtp_rxstat = models.CharField(_(u'sip rtp rx stat'), null=True, max_length=30) |
1763
|
|
|
sip_rtp_txstat = models.CharField(_(u'sip rtp tx stat'), null=True, max_length=30) |
1764
|
|
|
switchname = models.CharField(_(u"switchname"), null=True, default="", max_length=100) |
1765
|
|
|
switch_ipv4 = models.CharField(_(u"switch ipv4"), null=True, default="", max_length=100) |
1766
|
|
|
hangup_disposition = models.CharField(_(u"hangup disposition"), null=True, default="", max_length=100) |
1767
|
|
|
sip_hangup_cause = models.CharField(_(u"SIP hangup cause"), null=True, default="", max_length=100) |
1768
|
|
|
sell_destination = models.CharField(_(u'sell destination'), blank=True, default='', null=True, max_length=128, db_index=True) |
1769
|
|
|
cost_destination = models.CharField(_(u'cost destination'), blank=True, default='', null=True, max_length=128, db_index=True) |
1770
|
|
|
|
1771
|
|
|
class Meta: |
1772
|
|
|
db_table = 'cdr' |
1773
|
|
|
ordering = ('start_stamp', 'customer') |
1774
|
|
|
verbose_name = _(u"CDR") |
1775
|
|
|
verbose_name_plural = _(u"CDRs") |
1776
|
|
|
|
1777
|
|
|
def __unicode__(self): |
1778
|
|
|
if self.start_stamp: |
1779
|
|
|
return self.start_stamp |
1780
|
|
|
else: |
1781
|
|
|
return self.custom_alias_name |
1782
|
|
|
|
1783
|
|
|
def hangup_cause_colored(self): |
1784
|
|
|
if self.billsec == 0: |
1785
|
|
|
color = "red" |
1786
|
|
|
else: |
1787
|
|
|
color = "green" |
1788
|
|
|
return " <span style=color:%s>%s</span>" % (color, self.hangup_cause) |
1789
|
|
|
hangup_cause_colored.allow_tags = True |
1790
|
|
|
|
1791
|
|
|
@property |
1792
|
|
|
def daily_total_answered_calls(self): |
1793
|
|
|
return qsstats.QuerySetStats(self.objects.all().exclude(effective_duration="0").filter(hangup_cause="NORMAL_CLEARING"), 'start_stamp', aggregate=Count('id')).this_day() |
1794
|
|
|
|
1795
|
|
|
@property |
1796
|
|
|
def daily_total_calls(self): |
1797
|
|
|
return qsstats.QuerySetStats(self.objects.all(), 'start_stamp', aggregate=Count('id')).this_day() |
1798
|
|
|
|
1799
|
|
|
@property |
1800
|
|
|
def daily_total_effective_duration_calls(self): |
1801
|
|
|
return qsstats.QuerySetStats(self.objects.all().exclude(effective_duration="0").filter(hangup_cause="NORMAL_CLEARING"), 'start_stamp', aggregate=Sum('effective_duration')).this_day() |
1802
|
|
|
|
1803
|
|
|
@property |
1804
|
|
|
def daily_total_sell_calls(self): |
1805
|
|
|
return qsstats.QuerySetStats(self.objects.all().exclude(effective_duration="0").filter(hangup_cause="NORMAL_CLEARING"), 'start_stamp', aggregate=Sum('total_sell')).this_day() |
1806
|
|
|
|
1807
|
|
|
@property |
1808
|
|
|
def daily_total_cost_calls(self): |
1809
|
|
|
return qsstats.QuerySetStats(self.objects.all().exclude(effective_duration="0").filter(hangup_cause="NORMAL_CLEARING"), 'start_stamp', aggregate=Sum('total_cost')).this_day() |
1810
|
|
|
|
1811
|
|
|
def _get_min_effective_duration(self): |
1812
|
|
|
if self.effective_duration: |
1813
|
|
|
min = int(self.effective_duration / 60) |
1814
|
|
|
sec = int(self.effective_duration % 60) |
1815
|
|
|
else: |
1816
|
|
|
min = 0 |
1817
|
|
|
sec = 0 |
1818
|
|
|
|
1819
|
|
|
return "%02d:%02d" % (min, sec) |
1820
|
|
|
min_effective_duration = property(_get_min_effective_duration) |
1821
|
|
|
|
1822
|
|
|
def _get_total_sell(self): |
1823
|
|
|
if self.rate and self.rate != 0: |
1824
|
|
|
totalsell = decimal.Decimal(self.billsec) * decimal.Decimal(self.rate) / 60 |
1825
|
|
|
else: |
1826
|
|
|
totalsell = 0.000000 |
1827
|
|
|
if self.init_block: |
1828
|
|
|
totalsell = decimal.Decimal(totalsell) + decimal.Decimal(self.init_block) |
1829
|
|
|
return round(totalsell, 6) |
1830
|
|
|
total_sell_py = property(_get_total_sell) |
1831
|
|
|
|
1832
|
|
|
def _get_total_cost(self): |
1833
|
|
|
if self.cost_rate: |
1834
|
|
|
totalcost = decimal.Decimal(self.effective_duration) * decimal.Decimal(self.cost_rate) / 60 |
1835
|
|
|
else: |
1836
|
|
|
totalcost = 0.000000 |
1837
|
|
|
return round(totalcost, 6) |
1838
|
|
|
total_cost_py = property(_get_total_cost) |
1839
|
|
|
|
1840
|
|
|
def _get_effective_duration(self): |
1841
|
|
|
if self.effectiv_duration: |
1842
|
|
|
effdur = math.ceil(self.effectiv_duration / 1000.0) |
1843
|
|
|
else: |
1844
|
|
|
effdur = 0 |
1845
|
|
|
return int(effdur) |
1846
|
|
|
effective_duration_py = property(_get_effective_duration) |
1847
|
|
|
|
1848
|
|
|
def _get_billsec(self): |
1849
|
|
|
if self.block_min_duration and self.effective_duration: |
1850
|
|
|
if self.effective_duration < self.block_min_duration: |
1851
|
|
|
billsec = self.block_min_duration |
1852
|
|
|
else: |
1853
|
|
|
billsec = math.ceil(self.effective_duration / self.block_min_duration) * self.block_min_duration |
1854
|
|
|
else: |
1855
|
|
|
billsec = self.effective_duration |
1856
|
|
|
return int(billsec) |
1857
|
|
|
billsec_py = property(_get_billsec) |
1858
|
|
|
|
1859
|
|
|
def success_cdr(self): |
1860
|
|
|
return self.CDR.objects.exclude(effective_duration="0") |
1861
|
|
|
|
1862
|
|
|
# STATS |
1863
|
|
|
|
1864
|
|
|
|
1865
|
|
|
class DimDate(models.Model): |
1866
|
|
|
""" Date dimension """ |
1867
|
|
|
date = models.DateTimeField() |
1868
|
|
|
day = models.CharField(_(u'day'), max_length=2) |
1869
|
|
|
day_of_week = models.CharField(_(u'day of the week'), max_length=30) |
1870
|
|
|
hour = models.CharField(_(u'hour'), max_length=2, null=True, blank=True) |
1871
|
|
|
month = models.CharField(_(u'month'), max_length=2) |
1872
|
|
|
quarter = models.CharField(_(u'quarter'), max_length=2) |
1873
|
|
|
year = models.CharField(_(u'year'), max_length=4) |
1874
|
|
|
|
1875
|
|
|
class Meta: |
1876
|
|
|
db_table = 'date_dimension' |
1877
|
|
|
ordering = ('date',) |
1878
|
|
|
verbose_name = _(u"date dimension") |
1879
|
|
|
verbose_name_plural = _(u"date dimensions") |
1880
|
|
|
|
1881
|
|
|
def __unicode__(self): |
1882
|
|
|
return u"%s" % self.date |
1883
|
|
|
|
1884
|
|
|
|
1885
|
|
|
class DimCustomerHangupcause(models.Model): |
1886
|
|
|
""" Dimension Customer / Hangupcause Model """ |
1887
|
|
|
customer = models.ForeignKey(Company, verbose_name=_(u"customer")) |
1888
|
|
|
destination = models.CharField(_(u'destination'), max_length=250, null=True, blank=True) |
1889
|
|
|
hangupcause = models.CharField(_(u'hangupcause'), max_length=100, null=True, blank=True) |
1890
|
|
|
date = models.ForeignKey(DimDate, verbose_name=_(u"date")) |
1891
|
|
|
total_calls = models.IntegerField(_(u"total calls")) |
1892
|
|
|
|
1893
|
|
|
class Meta: |
1894
|
|
|
db_table = 'dim_customer_hangupcause' |
1895
|
|
|
ordering = ('date', 'customer', 'hangupcause') |
1896
|
|
|
verbose_name = _(u"Customer Hangupcause stats") |
1897
|
|
|
verbose_name_plural = _(u"Customer Hangupcause stats") |
1898
|
|
|
|
1899
|
|
|
def __unicode__(self): |
1900
|
|
|
return u"%s -c: %s -h: %s" % (self.date, self.customer, self.hangupcause) |
1901
|
|
|
|
1902
|
|
|
|
1903
|
|
|
class DimCustomerSipHangupcause(models.Model): |
1904
|
|
|
""" Dimension Customer / SIP Hangupcause Model """ |
1905
|
|
|
customer = models.ForeignKey(Company, verbose_name=_(u"customer")) |
1906
|
|
|
destination = models.CharField(_(u'destination'), max_length=250, null=True, blank=True) |
1907
|
|
|
sip_hangupcause = models.CharField(_(u'sip hangupcause'), max_length=100, null=True, blank=True) |
1908
|
|
|
date = models.ForeignKey(DimDate, verbose_name=_(u"date")) |
1909
|
|
|
total_calls = models.IntegerField(_(u"total calls")) |
1910
|
|
|
|
1911
|
|
|
class Meta: |
1912
|
|
|
db_table = 'dim_customer_sip_hangupcause' |
1913
|
|
|
ordering = ('date', 'customer', 'sip_hangupcause') |
1914
|
|
|
verbose_name = _(u"Customer SIP Hangupcause stats") |
1915
|
|
|
verbose_name_plural = _(u"Customer SIP Hangupcause stats") |
1916
|
|
|
|
1917
|
|
|
def __unicode__(self): |
1918
|
|
|
return u"%s -c: %s -h: %s" % (self.date, self.customer, self.sip_hangupcause) |
1919
|
|
|
|
1920
|
|
|
|
1921
|
|
|
class DimProviderHangupcause(models.Model): |
1922
|
|
|
""" Dimension Provider / Hangupcause Model """ |
1923
|
|
|
provider = models.ForeignKey(Company, verbose_name=_(u"provider")) |
1924
|
|
|
destination = models.CharField(_(u'destination'), max_length=250, null=True, blank=True) |
1925
|
|
|
hangupcause = models.CharField(_(u'hangupcause'), max_length=100, null=True, blank=True) |
1926
|
|
|
date = models.ForeignKey(DimDate, verbose_name=_(u"date")) |
1927
|
|
|
total_calls = models.IntegerField(_(u"total calls")) |
1928
|
|
|
|
1929
|
|
|
class Meta: |
1930
|
|
|
db_table = 'dim_provider_hangupcause' |
1931
|
|
|
ordering = ('date', 'provider', 'hangupcause') |
1932
|
|
|
verbose_name = _(u"Provider Hangupcause stats") |
1933
|
|
|
verbose_name_plural = _(u"Provider Hangupcause stats") |
1934
|
|
|
|
1935
|
|
|
def __unicode__(self): |
1936
|
|
|
return u"%s -c: %s -h: %s" % (self.date, self.provider, self.hangupcause) |
1937
|
|
|
|
1938
|
|
|
|
1939
|
|
|
class DimProviderSipHangupcause(models.Model): |
1940
|
|
|
""" Dimension Provider / SIP Hangupcause Model """ |
1941
|
|
|
provider = models.ForeignKey(Company, verbose_name=_(u"provider")) |
1942
|
|
|
destination = models.CharField(_(u'destination'), max_length=250, null=True, blank=True) |
1943
|
|
|
sip_hangupcause = models.CharField(_(u'sip hangupcause'), max_length=100, null=True, blank=True) |
1944
|
|
|
date = models.ForeignKey(DimDate, verbose_name=_(u"date")) |
1945
|
|
|
total_calls = models.IntegerField(_(u"total calls")) |
1946
|
|
|
|
1947
|
|
|
class Meta: |
1948
|
|
|
db_table = 'dim_provider_sip_hangupcause' |
1949
|
|
|
ordering = ('date', 'provider', 'sip_hangupcause') |
1950
|
|
|
verbose_name = _(u"Provider SIP Hangupcause stats") |
1951
|
|
|
verbose_name_plural = _(u"Provider SIP Hangupcause stats") |
1952
|
|
|
|
1953
|
|
|
def __unicode__(self): |
1954
|
|
|
return u"%s -c: %s -h: %s" % (self.date, self.provider, self.sip_hangupcause) |
1955
|
|
|
|
1956
|
|
|
|
1957
|
|
|
class DimCustomerDestination(models.Model): |
1958
|
|
|
""" Dimension Customer / Destination Model """ |
1959
|
|
|
customer = models.ForeignKey(Company, verbose_name=_(u"customer")) |
1960
|
|
|
destination = models.CharField(_(u'destination'), max_length=250, null=True, blank=True) |
1961
|
|
|
date = models.ForeignKey(DimDate, verbose_name=_(u"date")) |
1962
|
|
|
total_calls = models.IntegerField(_(u"total calls"), default=0) |
1963
|
|
|
success_calls = models.IntegerField(_(u"success calls"), default=0) |
1964
|
|
|
total_duration = models.IntegerField(_(u"total duration"), default=0) |
1965
|
|
|
avg_duration = models.IntegerField(_(u"average duration"), default=0) |
1966
|
|
|
max_duration = models.IntegerField(_(u"max duration"), default=0) |
1967
|
|
|
min_duration = models.IntegerField(_(u"min duration"), default=0) |
1968
|
|
|
total_sell = models.DecimalField(_(u'total sell'), max_digits=12, decimal_places=2) |
1969
|
|
|
total_cost = models.DecimalField(_(u'total cost'), max_digits=12, decimal_places=2) |
1970
|
|
|
|
1971
|
|
|
class Meta: |
1972
|
|
|
db_table = 'dim_customer_destination' |
1973
|
|
|
ordering = ('date', 'customer', 'destination') |
1974
|
|
|
verbose_name = _(u"Customer destination stats") |
1975
|
|
|
verbose_name_plural = _(u"Customer destination stats") |
1976
|
|
|
|
1977
|
|
|
def __unicode__(self): |
1978
|
|
|
return u"%s -c: %s -d: %s" % (self.date, self.customer, self.destination) |
1979
|
|
|
|
1980
|
|
|
def _get_margin(self): |
1981
|
|
|
if self.total_sell and self.total_cost: |
1982
|
|
|
margin = self.total_sell - self.total_cost |
1983
|
|
|
else: |
1984
|
|
|
margin = 0 |
1985
|
|
|
return round(margin, 2) |
1986
|
|
|
margin = property(_get_margin) |
1987
|
|
|
|
1988
|
|
|
|
1989
|
|
|
class DimProviderDestination(models.Model): |
1990
|
|
|
""" Dimension Provider / Destination Model """ |
1991
|
|
|
provider = models.ForeignKey(Company, verbose_name=_(u"provider")) |
1992
|
|
|
destination = models.CharField(_(u'destination'), max_length=250, null=True, blank=True) |
1993
|
|
|
date = models.ForeignKey(DimDate, verbose_name=_(u"date")) |
1994
|
|
|
total_calls = models.IntegerField(_(u"total calls"), default=0) |
1995
|
|
|
success_calls = models.IntegerField(_(u"success calls"), default=0) |
1996
|
|
|
total_duration = models.IntegerField(_(u"total duration"), default=0) |
1997
|
|
|
avg_duration = models.IntegerField(_(u"average duration"), default=0) |
1998
|
|
|
max_duration = models.IntegerField(_(u"max duration"), default=0) |
1999
|
|
|
min_duration = models.IntegerField(_(u"min duration"), default=0) |
2000
|
|
|
total_sell = models.DecimalField(_(u'total sell'), max_digits=12, decimal_places=2) |
2001
|
|
|
total_cost = models.DecimalField(_(u'total cost'), max_digits=12, decimal_places=2) |
2002
|
|
|
|
2003
|
|
|
class Meta: |
2004
|
|
|
db_table = 'dim_provider_destination' |
2005
|
|
|
ordering = ('date', 'provider', 'destination') |
2006
|
|
|
verbose_name = _(u"Provider destination stats") |
2007
|
|
|
verbose_name_plural = _(u"Provider destination stats") |
2008
|
|
|
|
2009
|
|
|
def __unicode__(self): |
2010
|
|
|
return u"%s -p: %s -d: %s" % (self.date, self.provider, self.destination) |
2011
|
|
|
|
2012
|
|
|
def get_daily_providers_stats(self, today, delta, interval): |
2013
|
|
|
qs = self.model._default_manager.filter(date__lte=lastday) |
2014
|
|
|
qss = qsstats.QuerySetStats(qs, 'date') |
2015
|
|
|
lastday = today - datetime.timedelta(days=delta) |
2016
|
|
|
return qss.time_series(lastday, today, interval) |
2017
|
|
|
|
2018
|
|
|
def get_current_week_daily_provider_stats(self, period, interval): |
2019
|
|
|
today = datetime.date.today() |
2020
|
|
|
return self.get_daily_providers_stats(today, period, interval) |
2021
|
|
|
|
2022
|
|
|
def get_day_total_calls(self): |
2023
|
|
|
qs = DimProviderDestination.objects.all() |
2024
|
|
|
day_qs = qs.values('date').annotate(day_total_calls=Sum('total_calls'), day_success_calls=Sum('success_calls'), day_total_duration=Sum('total_duration'), day_total_sell=Sum('total_sell'), day_total_cost=Sum('total_cost')).order_by('date') |
2025
|
|
|
return [t[1] for t in day_qs] |
2026
|
|
|
|