- |
+ |
{% if perms.abonapp.add_abon %}
{% trans 'Add abon' %}
@@ -134,16 +143,27 @@
{% include 'toolbar_page.html' with pag=peoples %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/abonapp/templates/abonapp/service.html b/abonapp/templates/abonapp/service.html
new file mode 100644
index 0000000..976b982
--- /dev/null
+++ b/abonapp/templates/abonapp/service.html
@@ -0,0 +1,119 @@
+{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %}
+{% load i18n %}
+{% block content %}
+
+
+
+
+
+
+ {% trans "Subscriber's service" %}
+
+
+ {% if abon_tariff %}
+
+
+ - {% trans 'Service' %}
+ -
+ {% if abon_tariff.tariff %}
+ {% if perms.tariff_app.change_tariff %}
+
+ {{ abon_tariff.tariff.title }}
+
+ {% else %}
+ {{ abon_tariff.tariff.title }}
+ {% endif %}
+ {% else %}
+ {% trans 'We have a problem in DB: AbonTariff instance has no related to service' %}
+ {% endif %}
+
+ - {% trans 'Sum' %}
+ - {{ abon_tariff.tariff.amount }} {% trans 'currency' %}.
+
+ - {% trans 'Input speed' %}
+ - {{ abon_tariff.tariff.speedIn }}
+
+ - {% trans 'Output speed' %}
+ - {{ abon_tariff.tariff.speedOut }}
+
+ - {% trans 'Date of start' %}
+ - {{ abon_tariff.time_start|date:"d E Y, l H:i" }}
+
+ - {% trans 'Works until' %}
+ - {{ abon_tariff.deadline|date:"d E Y, l H:i" }}
+
+
+
+ {{ abon_tariff.tariff.descr }}
+
+
+ {% else %}
+ {% trans 'Subscriber has no service' %}.
+
+ {% trans 'Buy service' %}
+
+ {% endif %}
+
+ {% if abon_tariff %}
+
+ {% trans 'Finish service' %}
+
+ {% endif %}
+
+
+
+
+
+
+ Услуги для заказа
+
+
+
+
+
+ | {% trans 'Pick a service' %} |
+ {% trans 'Service' %} |
+ {% trans 'Price' %} |
+ {% trans 'Speed In' %} |
+ {% trans 'Speed Out' %} |
+
+
+
+ {% with can_ch_trf=perms.tariff_app.change_tariff %}
+ {% for service in services %}
+
+ |
+
+ |
+
+ {% if can_ch_trf %}
+ {{ service.title }}
+ {% else %}
+ {{ service.title }}
+ {% endif %}
+ |
+ {{ service.amount }} {% trans 'currency' %} |
+ {{ service.speedIn }} |
+ {{ service.speedOut }} |
+
+ {% empty %}
+ |
+ {% trans 'This group has no services' %}
+
+ {% trans 'Tariffs in groups' %}
+
+ |
+ {% endfor %}
+ {% endwith %}
+
+
+
+ {% trans 'Attach services to group' %}
+
+
+
+
+
+
+{% endblock %}
diff --git a/abonapp/templates/abonapp/services.html b/abonapp/templates/abonapp/services.html
deleted file mode 100644
index 47b67a9..0000000
--- a/abonapp/templates/abonapp/services.html
+++ /dev/null
@@ -1,101 +0,0 @@
-{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %}
-{% load i18n %}
-{% block content %}
-
-
-
-
-
- | {% trans 'Priority' %} |
- {% trans 'Service' %} |
- {% trans 'Sum' %} |
- {% trans 'Input speed' %} |
- {% trans 'Output speed' %} |
- {% trans 'Works until' %} |
- {% trans 'Do' %} |
-
-
-
-
- {% for trf in abon_tarifs %}
-
- | {{ trf.tariff_priority }} |
-
-
- {% if perms.tariff_app.change_tariff %}
-
- {{ trf.tariff.title }}
-
- {% else %}
- {{ trf.tariff.title }}
- {% endif %}
-
- |
- {{ trf.tariff.amount }} |
- {{ trf.tariff.speedIn }} |
- {{ trf.tariff.speedOut }} |
- {{ trf.deadline|date:"d E Y, l" }} |
- {% if trf.id != active_abontariff_id %}
-
-
- {% if perms.abonapp.can_activate_service %}
- {% if not active_abontariff_id %}
-
-
-
- {% endif %}
- {% endif %}
-
-
-
-
-
-
-
-
-
-
-
- {% if perms.abonapp.delete_abontariff %}
-
-
-
- {% endif %}
- |
- {% else %}
-
-
- {% trans 'Finish service' %}
-
- |
- {% endif %}
-
- {% empty %}
-
- | {% trans 'Services of subscribers not found' %}.
- {% if perms.abonapp.can_buy_tariff %}
- {% trans 'Buy' %}
- {% endif %}
- |
-
- {% endfor %}
-
- {% if perms.abonapp.can_buy_tariff %}
-
-
- |
-
- {% trans 'Buy service' %}
-
- |
-
-
- {% endif %}
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/abonapp/tests.py b/abonapp/tests.py
deleted file mode 100644
index b66baf8..0000000
--- a/abonapp/tests.py
+++ /dev/null
@@ -1,225 +0,0 @@
-from django.shortcuts import resolve_url
-from django.test import TestCase
-from django.test.client import Client
-from agent import NasNetworkError
-from .models import AbonTariff, Abon, AbonGroup, AbonRawPassword
-from tariff_app.models import Tariff
-from mydefs import LogicError
-
-
-class AbonTestCase(TestCase):
- def setUp(self):
- try:
- Tariff.objects.create(
- title='test_tariff',
- descr='taroff descr',
- speedIn=1.2,
- speedOut=3.0,
- amount=3
- )
- abon = Abon()
- abon.username = '1234567'
- abon.fio = 'mainuser'
- abon.telephone = '+79788328884'
- abon.set_password('ps')
- abon.is_superuser = True
- abon.save()
- abon_group = AbonGroup.objects.create(title='abon_group')
- abon_group.profiles.add(abon)
- except NasNetworkError:
- pass
-
- # проверка на пополнение счёта
- def test_add_ballance(self):
- try:
- abon = Abon.objects.get(username='1234567')
- ballance = abon.ballance
- abon.add_ballance(abon, 13, 'test pay')
- abon.save(update_fields=['ballance'])
- self.assertEqual(abon.ballance, ballance+13)
- ballance = abon.ballance
- abon.add_ballance(abon, 5.34, 'test float pay')
- abon.save(update_fields=['ballance'])
- self.assertEqual(abon.ballance, ballance+5.34)
- except NasNetworkError:
- pass
-
- # пробуем выбрать услугу
- def test_pick_tariff(self):
- try:
- tariff = Tariff.objects.get(title='test_tariff')
- abon = Abon.objects.get(username='1234567')
- try:
- abon.pick_tariff(tariff, abon)
- # нет денег, должно всплыть исключение и сюда дойти мы не должны
- self.assertFalse(True)
- except LogicError:
- pass
- act_tar = abon.active_tariff()
- # если недостаточно денег на счету
- assert abon.ballance <= tariff.amount
- # У абонента на счету 0, не должна быть куплена услуга
- self.assertEqual(act_tar, None)
- # Раз услуги нет то и доступа быть не должно
- self.assertTrue(not abon.is_access())
-
- # с деньгами
- abon.add_ballance(abon, 7.34, 'add pay for test pick tariff')
- abon.pick_tariff(tariff, abon)
- act_tar = abon.active_tariff()
- # должны получить указанную услугу
- self.assertEqual(act_tar, tariff)
- # и получить доступ
- self.assertTrue(abon.is_access())
- except NasNetworkError:
- pass
-
- # тестим очередь услуг
- def test_services_queue(self):
- abon = Abon.objects.get(username='1234567')
- tariff = Tariff.objects.get(title='test_tariff')
- abon.add_ballance(abon, 9, 'add pay for test services queue')
- abon.save()
- abon.pick_tariff(tariff, abon)
- abon.pick_tariff(tariff, abon)
- abon.pick_tariff(tariff, abon)
- # снять деньги должно было только за первый выбор, остальные стают в очередь услуг
- self.assertEqual(abon.ballance, 6)
-
- c = Client()
- # login
- c.post(resolve_url('acc_app:login'), {'login': '1234567', 'password': 'ps'})
- url = resolve_url('abonapp:compl_srv', gid=1, uid=1, srvid=1)
- resp = c.get(url)
- print('RESP:', resp)
- self.assertEqual(resp.status_code, 200)
- resp = c.post(url, data={
- 'finish_confirm': 'yes'
- })
- print('RESP:', resp)
- # при успешной остановке услуги идёт редирект на др страницу
- self.assertEqual(resp.status_code, 302)
- # текущей услуги быть не должно
- act_tar = abon.active_tariff()
- self.assertIsNone(act_tar)
- # не активных услуг останется 2
- noact_count = AbonTariff.objects.filter(abon=abon).filter(time_start=None).count()
- self.assertEqual(noact_count, 2)
-
- # проверяем платёжку alltime
- def test_allpay(self):
- from hashlib import md5
- from djing.settings import pay_SECRET, pay_SERV_ID
- import xmltodict
-
- def sig(act, pay_account, pay_id):
- md = md5()
- s = '_'.join((str(act), str(pay_account), pay_SERV_ID, str(pay_id), pay_SECRET))
- md.update(bytes(s, 'utf-8'))
- return md.hexdigest()
-
- c = Client()
- url = resolve_url('abonapp:terminal_pay')
- r = c.get(url, {
- 'ACT': 1, 'PAY_ACCOUNT': '1234567',
- 'SERVICE_ID': pay_SERV_ID,
- 'PAY_ID': 3561234,
- 'TRADE_POINT': 377,
- 'SIGN': sig(1, 1234567, 3561234)
- })
- xobj = xmltodict.parse(r.content)
- self.assertEqual(int(xobj['pay-response']['status_code']), 21)
- r = c.get(url, {
- 'ACT': 4, 'PAY_ACCOUNT': '1234567',
- 'SERVICE_ID': pay_SERV_ID,
- 'PAY_ID': 3561234,
- 'PAY_AMOUNT': 1.0,
- 'TRADE_POINT': 377,
- 'SIGN': sig(4, 1234567, 3561234)
- })
- xobj = xmltodict.parse(r.content)
- self.assertEqual(int(xobj['pay-response']['status_code']), 22)
- r = c.get(url, {
- 'ACT': 4, 'PAY_ACCOUNT': '1234567',
- 'SERVICE_ID': pay_SERV_ID,
- 'PAY_ID': 3561234,
- 'PAY_AMOUNT': 1.0,
- 'TRADE_POINT': 377,
- 'SIGN': sig(4, 1234567, 3561234)
- })
- xobj = xmltodict.parse(r.content)
- self.assertEqual(int(xobj['pay-response']['status_code']), -100)
- r = c.get(url, {
- 'ACT': 7, 'PAY_ACCOUNT': '1234567',
- 'SERVICE_ID': pay_SERV_ID,
- 'PAY_ID': 3561234,
- 'PAY_AMOUNT': 1.0,
- 'TRADE_POINT': 377,
- 'SIGN': sig(7, 1234567, 3561234)
- })
- xobj = xmltodict.parse(r.content)
- self.assertEqual(int(xobj['pay-response']['status_code']), 11)
- abon = Abon.objects.get(username='1234567')
- self.assertEqual(abon.ballance, 1)
-
- # пробуем добавить группу абонентов
- def test_add_abongroup(self):
- abon = Abon.objects.get(username='1234567')
- ag = AbonGroup.objects.create(title='%&34%$&*(')
- ag.profiles.add(abon)
-
- # пробуем добавить абонента
- def test_add_abon(self):
- c = Client()
- c.login(username='1234567', password='ps')
- url = resolve_url('abonapp:add_abon', gid=1)
- r = c.get(url)
- # поглядим на страницу добавления абонента
- self.assertEqual(r.status_code, 200)
- r = c.post(url, {
- 'username': '123',
- 'password': 'ps',
- 'fio': 'Abon Fio',
- 'telephone': '+79783753914',
- 'is_active': True
- })
- self.assertEqual(r.status_code, 302)
- r = c.get(resolve_url('abonapp:add_abon', gid=324))
- self.assertEqual(r.status_code, 404)
- try:
- abn = Abon.objects.get(username='123')
- self.assertIsNotNone(abn)
- psw = AbonRawPassword.objects.get(account=abn, passw_text='ps')
- self.assertIsNotNone(psw)
- except Abon.DoesNotExist:
- # абонент должен был создаться
- self.assertTrue(False)
- except AbonRawPassword.DoesNotExist:
- # должен быть пароль абонента простым текстом
- self.assertTrue(False)
-
- # пробуем удалить абонента
- def test_view_delentity(self):
- c = Client()
- c.login(username='1234567', password='ps')
- url = resolve_url('abonapp:del_abon') + '?t=a&id=1'
- r = c.get('/abons/1/addabon')
-
-
-class AbonTariffTestCase(TestCase):
- def setUp(self):
- abon = Abon.objects.create(
- username='1234567',
- telephone='+79788328884'
- )
- tariff = Tariff.objects.create(
- title='test_tariff',
- descr='taroff descr',
- speedIn=1.2,
- speedOut=3.0,
- amount=3
- )
- AbonTariff.objects.create(
- abon=abon,
- tariff=tariff
- )
diff --git a/abonapp/urls_abon.py b/abonapp/urls_abon.py
index b93c5d3..2922a6b 100644
--- a/abonapp/urls_abon.py
+++ b/abonapp/urls_abon.py
@@ -6,6 +6,9 @@ urlpatterns = [
url(r'^$', views.peoples, name='people_list'),
url(r'^addabon$', views.addabon, name='add_abon'),
url(r'^services$', views.chgroup_tariff, name='ch_group_tariff'),
+ url(r'^street/add$', views.street_add, name='street_add'),
+ url(r'^street/edit', views.street_edit, name='street_edit'),
+ url(r'^street/(?P\d+)/delete$', views.street_del, name='street_del'),
url(r'^(?P\d+)$', views.abonhome, name='abon_home'),
url(r'^(?P\d+)/services$', views.abon_services, name='abon_services'),
@@ -15,21 +18,20 @@ urlpatterns = [
url(r'^(?P\d+)/addinvoice$', views.add_invoice, name='add_invoice'),
url(r'^(?P\d+)/pick$', views.pick_tariff, name='pick_tariff'),
- url(r'^(?P\d+)/chpriority$', views.chpriority, name='chpriority_tariff'),
url(r'^(?P\d+)/passport_view$', views.passport_view, name='passport_view'),
url(r'^(?P\d+)/complete_service(?P\d+)$', views.complete_service, name='compl_srv'),
- url(r'^(?P\d+)/activate_service(?P\d+)$', views.activate_service, name='activate_service'),
- url(r'^(?P\d+)/opt82$', views.opt82, name='opt82'),
url(r'^(?P\d+)/chart$', views.charts, name='charts'),
+ url(r'^(?P\d+)/dials$', views.dials, name='dials'),
url(r'^(?P\d+)/extra_field$', views.make_extra_field, name='extra_field'),
url(r'^(?P\d+)/extra_field/(?P\d+)/delete$', views.extra_field_delete, name='extra_field_delete'),
url(r'^(?P\d+)/extra_field/edit$', views.extra_field_change, name='extra_field_edit'),
- url(r'^(?P\d+)/unsubscribe_service(?P\d+)$', views.unsubscribe_service,
+ url(r'^(?P\d+)/unsubscribe_service(?P\d+)$', views.unsubscribe_service,
name='unsubscribe_service'),
url(r'^(?P\d+)/dev/$', views.dev, name='dev'),
url(r'^(?P\d+)/clear_dev/$', views.clear_dev, name='clear_dev'),
- url(r'^(?P\d+)/task_log$', views.task_log, name='task_log')
+ url(r'^(?P\d+)/task_log$', views.task_log, name='task_log'),
+ url(r'^(?P\d+)/user_dev$', views.save_user_dev_port, name='save_user_dev_port')
]
diff --git a/abonapp/views.py b/abonapp/views.py
index 7759ae7..a08d9ea 100644
--- a/abonapp/views.py
+++ b/abonapp/views.py
@@ -3,7 +3,8 @@ from json import dumps
from django.contrib.gis.shortcuts import render_to_text
from django.core.exceptions import PermissionDenied
from django.db import IntegrityError, ProgrammingError
-from django.db.models import Count
+from django.db.models import Count, Q
+from django.db.transaction import atomic
from django.shortcuts import render, redirect, get_object_or_404, resolve_url
from django.contrib.auth.decorators import login_required, permission_required
from django.utils import timezone
@@ -11,14 +12,17 @@ from django.http import HttpResponse
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
-from statistics.models import getModel
+from statistics.models import StatCache
from tariff_app.models import Tariff
from agent import NasFailedResult, Transmitter, NasNetworkError
from . import forms
from . import models
import mydefs
-from devapp.models import Device
-from datetime import datetime
+from devapp.models import Device, Port as DevPort
+from datetime import datetime, date
+from taskapp.models import Task
+from dialing_app.models import AsteriskCDR
+from statistics.models import getModel, get_dates
@login_required
@@ -31,8 +35,6 @@ def peoples(request, gid):
else:
peoples_list = peoples_list.filter(group=gid)
- StatModel = getModel()
-
# фильтр
dr, field = mydefs.order_helper(request)
if field:
@@ -42,10 +44,10 @@ def peoples(request, gid):
peoples_list = mydefs.pag_mn(request, peoples_list)
for abon in peoples_list:
if abon.ip_address is not None:
- traf = StatModel.objects.traffic_by_ip(abon.ip_address)
- if traf[1] is not None:
- abon.traf = traf[1]
- abon.is_online =traf[0]
+ try:
+ abon.stat_cache = StatCache.objects.get(ip=abon.ip_address)
+ except StatCache.DoesNotExist:
+ pass
except mydefs.LogicError as e:
messages.warning(request, e)
@@ -189,6 +191,7 @@ def delentity(request):
@login_required
@permission_required('abonapp.can_add_ballance')
+@atomic
def abonamount(request, gid, uid):
abon = get_object_or_404(models.Abon, pk=uid)
try:
@@ -242,16 +245,14 @@ def pay_history(request, gid, uid):
@login_required
@mydefs.only_admins
def abon_services(request, gid, uid):
+ grp = get_object_or_404(models.AbonGroup, pk=gid)
abon = get_object_or_404(models.Abon, pk=uid)
- abon_tarifs = models.AbonTariff.objects.filter(abon=uid)
- active_abontariff = abon_tarifs.exclude(time_start=None)
-
- return render(request, 'abonapp/services.html', {
+ return render(request, 'abonapp/service.html', {
'abon': abon,
- 'abon_tarifs': abon_tarifs,
- 'active_abontariff_id': active_abontariff[0].id if active_abontariff.count() > 0 else None,
- 'abon_group': abon.group
+ 'abon_tariff': abon.current_tariff,
+ 'abon_group': abon.group,
+ 'services': grp.tariffs.all()
})
@@ -262,20 +263,13 @@ def abonhome(request, gid, uid):
abon_group = get_object_or_404(models.AbonGroup, pk=gid)
frm = None
passw = None
- abon_device = None
try:
if request.method == 'POST':
if not request.user.has_perm('abonapp.change_abon'):
raise PermissionDenied
frm = forms.AbonForm(request.POST, instance=abon)
if frm.is_valid():
- # если нет option82, т.е. динамический ip то не сохраняем изменения ip
- if abon.opt82 is None:
- ip_str = request.POST.get('ip')
- if ip_str:
- abon.ip_address = ip_str
- else:
- abon.ip_address = None
+ abon.ip_address = request.POST.get('ip')
frm.save()
messages.success(request, _('edit abon success msg'))
else:
@@ -283,7 +277,8 @@ def abonhome(request, gid, uid):
else:
passw = models.AbonRawPassword.objects.get(account=abon).passw_text
frm = forms.AbonForm(instance=abon, initial={'password': passw})
- abon_device = models.AbonDevice.objects.get(abon=abon)
+ if abon.device is None:
+ messages.warning(request, _('User device was not found'))
except mydefs.LogicError as e:
messages.error(request, e)
passw = models.AbonRawPassword.objects.get(account=abon).passw_text
@@ -293,8 +288,6 @@ def abonhome(request, gid, uid):
messages.error(request, e)
except models.AbonRawPassword.DoesNotExist:
messages.warning(request, _('User has not have password, and cannot login'))
- except models.AbonDevice.DoesNotExist:
- messages.warning(request, _('User device was not found'))
except mydefs.MultipleException as errs:
for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
@@ -306,8 +299,8 @@ def abonhome(request, gid, uid):
'abon_group': abon_group,
'ip': abon.ip_address,
'is_bad_ip': getattr(abon, 'is_bad_ip', False),
- 'tech_form': forms.Opt82Form(instance=abon.opt82),
- 'device': abon_device.device if abon_device is not None else None
+ 'device': abon.device,
+ 'dev_ports': DevPort.objects.filter(device=abon.device) if abon.device else None
})
else:
return render(request, 'abonapp/viewAbon.html', {
@@ -318,40 +311,7 @@ def abonhome(request, gid, uid):
})
-@login_required
-@mydefs.only_admins
-def opt82(request, gid, uid):
- try:
- abon = models.Abon.objects.get(pk=uid)
- if request.method == 'POST':
- try:
- opt82_instance = models.Opt82.objects.get(
- mac=request.POST.get('mac'),
- port=request.POST.get('port')
- )
- except models.Opt82.DoesNotExist:
- frm = forms.Opt82Form(request.POST)
- if frm.is_valid():
- opt82_instance = frm.save()
- else:
- messages.error(request, _('fix form errors'))
- return redirect('abonapp:abon_home', gid=gid, uid=uid)
-
- abon.opt82 = opt82_instance
- else:
- act = request.GET.get('act')
- if act is not None and act == 'release':
- if abon.opt82 is not None:
- abon.opt82.delete()
- abon.opt82 = None
-
- abon.save(update_fields=['opt82'])
- except models.Abon.DoesNotExist:
- messages.error(request, _('User does not exist'))
- return redirect('abonapp:abon_home', gid=gid, uid=uid)
-
-
-@mydefs.require_ssl
+@atomic
def terminal_pay(request):
from .pay_systems import allpay
ret_text = allpay(request)
@@ -397,6 +357,7 @@ def add_invoice(request, gid, uid):
@login_required
@permission_required('abonapp.can_buy_tariff')
+@atomic
def pick_tariff(request, gid, uid):
grp = get_object_or_404(models.AbonGroup, pk=gid)
abon = get_object_or_404(models.Abon, pk=uid)
@@ -428,34 +389,14 @@ def pick_tariff(request, gid, uid):
return render(request, 'abonapp/buy_tariff.html', {
'tariffs': tariffs,
'abon': abon,
- 'abon_group': grp
+ 'abon_group': grp,
+ 'selected_tariff': mydefs.safe_int(request.GET.get('selected_tariff'))
})
-@login_required
-@mydefs.only_admins
-def chpriority(request, gid, uid):
- t = request.GET.get('t')
- act = request.GET.get('a')
-
- current_abon_tariff = get_object_or_404(models.AbonTariff, pk=t)
-
- try:
- if act == 'up':
- current_abon_tariff.priority_up()
- elif act == 'down':
- current_abon_tariff.priority_down()
- except (NasFailedResult, NasNetworkError) as e:
- messages.error(request, e)
- except mydefs.MultipleException as errs:
- for err in errs.err_list:
- messages.add_message(request, messages.constants.ERROR, err)
-
- return redirect('abonapp:abon_home', gid=gid, uid=uid)
-
-
@login_required
@permission_required('abonapp.can_complete_service')
+@atomic
def complete_service(request, gid, uid, srvid):
abtar = get_object_or_404(models.AbonTariff, pk=srvid)
abon = abtar.abon
@@ -513,44 +454,11 @@ def complete_service(request, gid, uid, srvid):
})
-@login_required
-@permission_required('abonapp.can_activate_service')
-def activate_service(request, gid, uid, srvid):
- abtar = get_object_or_404(models.AbonTariff, pk=srvid)
- amount = abtar.calc_amount_service()
-
- try:
- if request.method == 'POST':
- if request.POST.get('finish_confirm') != 'yes':
- return HttpResponse(_('Not confirmed'))
-
- abtar.activate(request.user)
- messages.success(request, _('Service has been activated successfully'))
- return redirect('abonapp:abon_services', gid, uid)
-
- except (NasFailedResult, mydefs.LogicError) as e:
- messages.error(request, e)
- except NasNetworkError as e:
- messages.warning(request, e)
- except mydefs.MultipleException as errs:
- for err in errs.err_list:
- messages.add_message(request, messages.constants.ERROR, err)
- calc_obj = abtar.tariff.get_calc_type()(abtar)
- return render(request, 'abonapp/activate_service.html', {
- 'abon': abtar.abon,
- 'abon_group': abtar.abon.group,
- 'abtar': abtar,
- 'amount': amount,
- 'diff': abtar.abon.ballance - amount,
- 'deadline': calc_obj.calc_deadline()
- })
-
-
@login_required
@permission_required('abonapp.delete_abontariff')
-def unsubscribe_service(request, gid, uid, srvid):
+def unsubscribe_service(request, gid, uid, abon_tariff_id):
try:
- get_object_or_404(models.AbonTariff, pk=int(srvid)).delete()
+ get_object_or_404(models.AbonTariff, pk=int(abon_tariff_id)).delete()
messages.success(request, _('User has been detached from service'))
except NasFailedResult as e:
messages.error(request, e)
@@ -559,7 +467,7 @@ def unsubscribe_service(request, gid, uid, srvid):
except mydefs.MultipleException as errs:
for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
- return redirect('abonapp:abon_home', gid=gid, uid=uid)
+ return redirect('abonapp:abon_services', gid=gid, uid=uid)
@login_required
@@ -610,7 +518,6 @@ def update_nas(request, group_id):
@login_required
@mydefs.only_admins
def task_log(request, gid, uid):
- from taskapp.models import Task
abon = get_object_or_404(models.Abon, pk=uid)
tasks = Task.objects.filter(abon=abon)
return render(request, 'abonapp/task_log.html', {
@@ -626,11 +533,15 @@ def passport_view(request, gid, uid):
try:
abon = models.Abon.objects.get(pk=uid)
if request.method == 'POST':
- frm = forms.PassportForm(request.POST)
+ try:
+ passport_instance = models.PassportInfo.objects.get(abon=abon)
+ except models.PassportInfo.DoesNotExist:
+ passport_instance = None
+ frm = forms.PassportForm(request.POST, instance=passport_instance)
if frm.is_valid():
- passp_instance = frm.save(commit=False)
- passp_instance.abon = abon
- passp_instance.save()
+ pi = frm.save(commit=False)
+ pi.abon = abon
+ pi.save()
messages.success(request, _('Passport information has been saved'))
return redirect('abonapp:passport_view', gid=gid, uid=uid)
else:
@@ -672,24 +583,20 @@ def chgroup_tariff(request, gid):
def dev(request, gid, uid):
abon_dev = None
try:
+ abon = models.Abon.objects.get(pk=uid)
if request.method == 'POST':
dev = Device.objects.get(pk=request.POST.get('dev'))
- abon = models.Abon.objects.get(pk=uid)
- try:
- models.AbonDevice.objects.get(device=dev, abon=abon)
- except models.AbonDevice.DoesNotExist:
- models.AbonDevice.objects.create(abon=abon, device=dev)
- messages.success(request, _('Device has successfully attached'))
+ abon.device = dev
+ abon.save(update_fields=['device'])
+ messages.success(request, _('Device has successfully attached'))
return redirect('abonapp:abon_home', gid=gid, uid=uid)
else:
- abon_dev = models.AbonDevice.objects.get(abon=uid).device
+ abon_dev = abon.device
except Device.DoesNotExist:
messages.warning(request, _('Device your selected already does not exist'))
except models.Abon.DoesNotExist:
messages.error(request, _('Abon does not exist'))
return redirect('abonapp:people_list', gid=gid)
- except models.AbonDevice.DoesNotExist:
- messages.warning(request, _('User device was not found'))
return render(request, 'abonapp/modal_dev.html', {
'devices': Device.objects.filter(user_group=gid),
'dev': abon_dev,
@@ -702,8 +609,8 @@ def dev(request, gid, uid):
def clear_dev(request, gid, uid):
try:
abon = models.Abon.objects.get(pk=uid)
- abdev = models.AbonDevice.objects.get(abon=abon)
- abdev.delete()
+ abon.device = None
+ abon.save(update_fields=['device'])
messages.success(request, _('Device has successfully unattached'))
except models.Abon.DoesNotExist:
messages.error(request, _('Abon does not exist'))
@@ -714,14 +621,16 @@ def clear_dev(request, gid, uid):
@login_required
@mydefs.only_admins
def charts(request, gid, uid):
- from statistics.models import getModel
- from datetime import datetime, date, time, timedelta
high = 100
- def byte_to_mbit(x):
- return ((x/60)*8)/2**20
+ wandate = request.GET.get('wantdate')
+ if wandate:
+ wandate = datetime.strptime(wandate, '%d%m%Y').date()
+ else:
+ wandate = date.today()
+
try:
- StatElem = getModel()
+ StatElem = getModel(wandate)
abon = models.Abon.objects.get(pk=uid)
if abon.group is None:
abon.group = models.AbonGroup.objects.get(pk=gid)
@@ -731,20 +640,18 @@ def charts(request, gid, uid):
if abon.ip_address is None:
charts_data = None
else:
- charts_data = StatElem.objects.filter(ip=abon.ip_address)
- #oct_limit = StatElem.percentile([cd.octets for cd in charts_data], 0.05)
- # ниже возвращаем пары значений трафика который переведён в mByte, и unix timestamp
- midnight = datetime.combine(date.today(), time.min)
- charts_data = [(cd.cur_time.timestamp()*1000, byte_to_mbit(cd.octets)) for cd in charts_data]
- if len(charts_data) > 0:
- charts_data.append( (charts_data[-1:][0][0], 0.0) )
- charts_data = ["{x: new Date(%d), y: %.2f}" % (cd[0], cd[1]) for cd in charts_data]
- charts_data.append("{x:new Date(%d),y:0}" % (int((midnight + timedelta(days=1)).timestamp()) * 1000))
+ charts_data = StatElem.objects.chart(
+ abon.ip_address,
+ count_of_parts=30,
+ want_date=wandate
+ )
abontariff = abon.active_tariff()
- high = abontariff.speedIn + abontariff.speedOut
- if high > 100:
- high = 100
+ if abontariff is not None:
+ trf = abontariff.tariff
+ high = trf.speedIn + trf.speedOut
+ if high > 100:
+ high = 100
except models.Abon.DoesNotExist:
messages.error(request, _('Abon does not exist'))
@@ -760,7 +667,8 @@ def charts(request, gid, uid):
'abon_group': abongroup,
'abon': abon,
'charts_data': ',\n'.join(charts_data) if charts_data is not None else None,
- 'high': high
+ 'high': high,
+ 'dates': get_dates()
})
@@ -799,7 +707,6 @@ def make_extra_field(request, gid, uid):
@permission_required('abonapp.change_extra_fields_model')
def extra_field_change(request, gid, uid):
extras = [(int(x), y) for x, y in zip(request.POST.getlist('ed'), request.POST.getlist('ex'))]
- print(extras)
try:
for ex in extras:
extra_field = models.ExtraFieldsModel.objects.get(pk=ex[0])
@@ -860,12 +767,115 @@ def abon_ping(request):
}))
+@login_required
+@mydefs.only_admins
+def dials(request, gid, uid):
+ abon = get_object_or_404(models.Abon, pk=uid)
+ if hasattr(abon.group, 'pk') and abon.group.pk != int(gid):
+ return redirect('abonapp:dials', abon.group.pk, abon.pk)
+ if abon.telephone is not None and abon.telephone != '':
+ tel = abon.telephone.replace('+', '')
+ logs = AsteriskCDR.objects.filter(
+ Q(src__contains=tel) | Q(dst__contains=tel)
+ )
+ logs = mydefs.pag_mn(request, logs)
+ else:
+ logs = None
+ return render(request, 'abonapp/dial_log.html', {
+ 'logs': logs,
+ 'abon_group': get_object_or_404(models.AbonGroup, pk=gid),
+ 'abon': abon
+ })
+
+
+@login_required
+@mydefs.only_admins
+def save_user_dev_port(request, gid, uid):
+ if request.method != 'POST':
+ messages.error(request, _('Method is not POST'))
+ return redirect('abonapp:abon_home', gid, uid)
+ user_port = mydefs.safe_int(request.POST.get('user_port'))
+ is_dynamic_ip = request.POST.get('is_dynamic_ip')
+ try:
+ if user_port == 0:
+ port = None
+ else:
+ port = DevPort.objects.get(pk=user_port)
+ abon = models.Abon.objects.get(pk=uid)
+ abon.dev_port = port
+ if abon.is_dynamic_ip != is_dynamic_ip:
+ abon.is_dynamic_ip = is_dynamic_ip
+ abon.save(update_fields=['dev_port', 'is_dynamic_ip'])
+ else:
+ abon.save(update_fields=['dev_port'])
+ messages.success(request, _('User port has been saved'))
+ except DevPort.DoesNotExist:
+ messages.error(request, _('Selected port does not exist'))
+ except models.Abon.DoesNotExist:
+ messages.error(request, _('User does not exist'))
+ return redirect('abonapp:abon_home', gid, uid)
+
+
+@login_required
+@permission_required('abonapp.add_abonstreet')
+def street_add(request, gid):
+ if request.method == 'POST':
+ frm = forms.AbonStreetForm(request.POST)
+ if frm.is_valid():
+ frm.save()
+ messages.success(request, _('Street successfully saved'))
+ return redirect('abonapp:people_list', gid)
+ else:
+ messages.error(request, _('fix form errors'))
+ else:
+ frm = forms.AbonStreetForm(initial={'group': gid})
+ return render_to_text('abonapp/modal_addstreet.html', {
+ 'form': frm,
+ 'gid': gid
+ }, request=request)
+
+
+@login_required
+@permission_required('abonapp.change_abonstreet')
+def street_edit(request, gid):
+ try:
+ if request.method == 'POST':
+ streets_pairs = [(int(sid), sname) for sid, sname in zip(request.POST.getlist('sid'), request.POST.getlist('sname'))]
+ for sid, sname in streets_pairs:
+ street = models.AbonStreet.objects.get(pk=sid)
+ street.name = sname
+ street.save()
+ messages.success(request, _('Streets has been saved'))
+ else:
+ return render_to_text('abonapp/modal_editstreet.html', {
+ 'gid': gid,
+ 'streets': models.AbonStreet.objects.filter(group=gid)
+ }, request=request)
+
+ except models.AbonStreet.DoesNotExist:
+ messages.error(request, _('One of these streets has not been found'))
+
+ return redirect('abonapp:people_list', gid)
+
+
+@login_required
+@permission_required('abonapp.delete_abonstreet')
+def street_del(request, gid, sid):
+ try:
+ models.AbonStreet.objects.get(pk=sid, group=gid).delete()
+ messages.success(request, _('The street successfully deleted'))
+ except models.AbonStreet.DoesNotExist:
+ messages.error(request, _('The street has not been found'))
+ return redirect('abonapp:people_list', gid)
+
+
+
# API's
def abons(request):
ablist = [{
'id': abn.pk,
- 'tarif_id': abn.active_tariff().pk if abn.active_tariff() else 0,
+ 'tarif_id': abn.active_tariff().tariff.pk if abn.active_tariff() is not None else 0,
'ip': abn.ip_address.int_ip(),
'is_active': abn.is_active
} for abn in models.Abon.objects.all()]
@@ -887,5 +897,5 @@ def abons(request):
def search_abon(request):
word = request.GET.get('s')
results = models.Abon.objects.filter(fio__icontains=word)[:8]
- results = [{'id': usr.pk, 'name': usr.username, 'fio': usr.fio} for usr in results]
+ results = [{'id': usr.pk, 'text': "%s: %s" % (usr.username, usr.fio)} for usr in results]
return HttpResponse(dumps(results, ensure_ascii=False))
diff --git a/accounts_app/locale/ru/LC_MESSAGES/django.po b/accounts_app/locale/ru/LC_MESSAGES/django.po
index ba3578d..d3c7a5c 100644
--- a/accounts_app/locale/ru/LC_MESSAGES/django.po
+++ b/accounts_app/locale/ru/LC_MESSAGES/django.po
@@ -23,10 +23,6 @@ msgstr ""
msgid "Users must have an telephone number"
msgstr "У пользователей должен быть номер телефона"
-#: accounts_app/models.py:52
-msgid "Telephone number"
-msgstr "Номер телефона"
-
#: accounts_app/templates/accounts/group.html:7
#: accounts_app/templates/accounts/group_list.html:7
msgid "Administrators"
@@ -81,7 +77,7 @@ msgstr "Добавить группу"
#: accounts_app/templates/accounts/index.html:8
#: accounts_app/templates/accounts/settings/ch_info.html:37
msgid "Telephone"
-msgstr "Номер телефона"
+msgstr "Телефон"
#: accounts_app/templates/accounts/index.html:12
#: accounts_app/templates/accounts/login.html:35
@@ -140,27 +136,35 @@ msgstr "Старый пароль"
msgid "New password"
msgstr "Новый пароль"
-#: accounts_app/views.py:43
+#: accounts_app/views.py:42
msgid "Wrong login or password, please try again"
msgstr "Неправильный логин или пароль, попробуйте ещё раз"
-#: accounts_app/views.py:137
+#: accounts_app/views.py:141
+msgid "New password is empty, fill it"
+msgstr "Новый пароль пустой, придумайте себе пароль"
+
+#: accounts_app/views.py:143
msgid "Wrong password"
msgstr "Неправильный пароль"
-#: accounts_app/views.py:162
+#: accounts_app/views.py:145
+msgid "Empty password, fill it"
+msgstr "Пустой пароль, впишите что-то в пароль"
+
+#: accounts_app/views.py:168
msgid "You forget specify a password for the new account"
msgstr "Забыли указать пароль для нового аккаунта"
-#: accounts_app/views.py:165
+#: accounts_app/views.py:171
msgid "You forget to repeat a password for the new account"
msgstr "Забыли повторить пароль для нового аккаунта"
-#: accounts_app/views.py:174
+#: accounts_app/views.py:180
msgid "Subscriber with this name already exist"
msgstr "Пользователь с таким именем уже есть"
-#: accounts_app/views.py:176
+#: accounts_app/views.py:182
msgid "Passwords does not match, try again"
msgstr "Пароли не совпадают, попробуйте ещё раз"
@@ -184,3 +188,9 @@ msgstr "Редактировать"
msgid "Set a task"
msgstr "Дать задачу"
+
+msgid "Please select an image"
+msgstr "Пожалуйста выберите изображение"
+
+msgid "Avatar successfully changed"
+msgstr "Аватар успешно изменён"
diff --git a/accounts_app/migrations/0007_auto_20170816_1109.py b/accounts_app/migrations/0007_auto_20170816_1109.py
new file mode 100644
index 0000000..d9a26e3
--- /dev/null
+++ b/accounts_app/migrations/0007_auto_20170816_1109.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9 on 2017-08-16 11:09
+from __future__ import unicode_literals
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('accounts_app', '0006_auto_20170416_1029'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='userprofile',
+ name='telephone',
+ field=models.CharField(max_length=16, validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')], verbose_name='Телефон'),
+ ),
+ ]
diff --git a/accounts_app/models.py b/accounts_app/models.py
index f630c8a..2508257 100644
--- a/accounts_app/models.py
+++ b/accounts_app/models.py
@@ -49,7 +49,7 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
is_admin = models.BooleanField(default=False)
telephone = models.CharField(
max_length=16,
- verbose_name=_('Telephone number'),
+ verbose_name=_('Telephone'),
#unique=True,
validators=[RegexValidator('^\+[7,8,9,3]\d{10,11}$')]
)
diff --git a/accounts_app/templates/accounts/index.html b/accounts_app/templates/accounts/index.html
index 1ab3684..b90ee3b 100644
--- a/accounts_app/templates/accounts/index.html
+++ b/accounts_app/templates/accounts/index.html
@@ -2,6 +2,7 @@
{% load i18n %}
{% block content %}
+
@@ -32,5 +33,6 @@
{% endif %}
+
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/accounts_app/views.py b/accounts_app/views.py
index b8c8961..0227436 100644
--- a/accounts_app/views.py
+++ b/accounts_app/views.py
@@ -4,7 +4,6 @@ from django.contrib.auth import authenticate, login, logout
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import NoReverseMatch
from django.shortcuts import render, redirect, get_object_or_404, resolve_url
-from django.http import Http404
from django.contrib.auth.models import Group, Permission
from django.contrib import messages
from django.utils.translation import ugettext as _
@@ -103,15 +102,20 @@ def chgroup(request, uid):
@mydefs.only_admins
def ch_ava(request):
if request.method == 'POST':
- user = request.user
- if user.avatar:
- user.avatar.delete()
- photo = Photo()
- photo.image = request.FILES.get('avatar')
- photo.save()
- user.avatar = photo
- user.save(update_fields=['avatar'])
- request.user = user
+ phname = request.FILES.get('avatar')
+ if phname is None:
+ messages.error(request, _('Please select an image'))
+ else:
+ user = request.user
+ if user.avatar:
+ user.avatar.delete()
+ photo = Photo()
+ photo.image = phname
+ photo.save()
+ user.avatar = photo
+ user.save(update_fields=['avatar'])
+ request.user = user
+ messages.success(request, _('Avatar successfully changed'))
return render(request, 'accounts/settings/ch_info.html', {
'user': request.user
@@ -129,14 +133,21 @@ def ch_info(request):
user.telephone = request.POST.get('telephone')
psw = request.POST.get('oldpasswd')
- if psw != '':
+ if psw != '' and psw is not None:
if user.check_password(psw):
newpasswd = request.POST.get('newpasswd')
- user.set_password(newpasswd)
+ if newpasswd != '' and newpasswd is not None:
+ user.set_password(newpasswd)
+ user.save()
+ request.user = user
+ logout(request)
+ return redirect('acc_app:other_profile', uid=user.pk)
+ else:
+ messages.error(request, _('New password is empty, fill it'))
else:
messages.error(request, _('Wrong password'))
- user.save()
- request.user = user
+ else:
+ messages.warning(request, _('Empty password, fill it'))
return render(request, 'accounts/settings/ch_info.html', {
'user': request.user
diff --git a/agent/commands/dhcp.py b/agent/commands/dhcp.py
new file mode 100644
index 0000000..fd39c4e
--- /dev/null
+++ b/agent/commands/dhcp.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+from django.core.exceptions import MultipleObjectsReturned
+from django.utils.translation import ugettext as _
+from abonapp.models import Abon
+from devapp.models import Device, Port
+
+
+def dhcp_commit(client_ip, client_mac, switch_mac, switch_port):
+ try:
+ dev = Device.objects.get(mac_addr=switch_mac)
+ mngr_class = dev.get_manager_klass()
+
+ port = _('')
+ if mngr_class.is_use_device_port():
+ port = Port.objects.get(device=dev, num=switch_port)
+ abon = Abon.objects.get(dev_port=port, device=dev)
+ else:
+ abon = Abon.objects.get(device=dev)
+ if not abon.is_dynamic_ip:
+ print('D:', _('User settings is not dynamic'))
+ return
+ if not abon.is_access():
+ print('D:', _('User is not access to service'))
+ return
+ abon.ip_address = client_ip
+ abon.is_dhcp = True
+ abon.save(update_fields=['ip_address'])
+ print('S:', _("Ip address:'%s' update for '%s' successfull, on port: %s") % (client_ip, abon.get_short_name(), port))
+ except Abon.DoesNotExist:
+ print('N:', _("User with device '%s' does not exist") % dev)
+ except Device.DoesNotExist:
+ print('N:', _('Device with mac %s not found') % switch_mac)
+ except Port.DoesNotExist:
+ print('N:', _('Port %d on device with mac %s does not exist') % (int(switch_port), switch_mac))
+ except MultipleObjectsReturned as e:
+ print('E:', 'MultipleObjectsReturned:', type(e), e)
+
+
+def dhcp_expiry(client_ip):
+ try:
+ abon = Abon.objects.get(ip_address=client_ip)
+ abon.ip_address = None
+ abon.is_dhcp = True
+ abon.save(update_fields=['ip_address'])
+ except Abon.DoesNotExist:
+ pass
+
+
+def dhcp_release(client_ip):
+ dhcp_expiry(client_ip)
diff --git a/agent/core.py b/agent/core.py
index 8561b56..756d68e 100644
--- a/agent/core.py
+++ b/agent/core.py
@@ -99,3 +99,34 @@ class BaseTransmitter(metaclass=ABCMeta):
:param count: количество пингов
:return: None если не пингуется, иначе кортеж, в котором (сколько вернулось, сколько было отправлено)
"""
+
+ @abstractmethod
+ def read_users(self):
+ """
+ Читаем пользователей с NAS
+ :return: список AbonStruct
+ """
+
+ def _diff_users(self, users_from_db):
+ """
+ :param users_from_db: QuerySet всех абонентов у которых может быть обслуживание
+ :return: на выходе получаем абонентов которых надо добавить в nas и которых надо удалить
+ """
+ users_from_db = [ab.build_agent_struct() for ab in users_from_db if ab.is_access()]
+ users_from_db = set([ab for ab in users_from_db if ab is not None and ab.tariff is not None])
+ users_from_nas = set(self.read_users())
+ list_for_del = (users_from_db ^ users_from_nas) - users_from_db
+ list_for_add = users_from_db - users_from_nas
+ return list_for_add, list_for_del
+
+ def sync_nas(self, users_from_db):
+ list_for_add, list_for_del = self._diff_users(users_from_db)
+ print('FOR DELETE')
+ for ld in list_for_del:
+ print(ld)
+ print('FOR ADD')
+ for la in list_for_add:
+ print(la)
+ self.remove_user_range( list_for_del )
+ self.add_user_range( list_for_add )
+
diff --git a/agent/mod_mikrotik.py b/agent/mod_mikrotik.py
index 1b09957..e1345b3 100644
--- a/agent/mod_mikrotik.py
+++ b/agent/mod_mikrotik.py
@@ -5,13 +5,13 @@ from abc import ABCMeta
from hashlib import md5
from .core import BaseTransmitter, NasFailedResult, NasNetworkError
from mydefs import ping
-from .structs import TariffStruct, AbonStruct, IpStruct, ShapeItem
+from .structs import TariffStruct, AbonStruct, IpStruct
from . import settings
from djing.settings import DEBUG
import re
-#DEBUG=False
+#DEBUG=True
LIST_USERS_ALLOWED = 'DjingUsersAllowed'
LIST_USERS_BLOCKED = 'DjingUsersBlocked'
@@ -33,7 +33,7 @@ class ApiRos:
md.update(bytes(pwd, 'utf-8'))
md.update(chal)
for r in self.talk_iter(["/login", "=name=" + username,
- "=response=00" + binascii.hexlify(md.digest()).decode('utf-8')]): pass
+ "=response=00" + binascii.hexlify(md.digest()).decode('utf-8')]): pass
def talk_iter(self, words):
if self.writeSentence(words) == 0: return
@@ -190,28 +190,29 @@ class TransmitterManager(BaseTransmitter, metaclass=ABCMeta):
res = text_speed_digit
elif text_append == 'k':
res = text_speed_digit / 1000
- #elif text_append == 'G':
+ # elif text_append == 'G':
# res = text_speed_digit * 0x400
else:
- res = float(re.sub(r'[a-zA-Z]', '', text_speed)) / 1000**2
+ res = float(re.sub(r'[a-zA-Z]', '', text_speed)) / 1000 ** 2
return res
+ speeds = info['=max-limit'].split('/')
+ t = TariffStruct(
+ speedIn=parse_speed(speeds[1]),
+ speedOut=parse_speed(speeds[0])
+ )
try:
- speeds = info['=max-limit'].split('/')
- t = TariffStruct(
- speedIn=parse_speed(speeds[1]),
- speedOut=parse_speed(speeds[0])
- )
a = AbonStruct(
uid=int(info['=name'][3:]),
- #FIXME: тут в разных микротиках или =target-addresses или =target
+ # FIXME: тут в разных микротиках или =target-addresses или =target
ip=info['=target'][:-3],
tariff=t,
is_active=False if info['=disabled'] == 'false' else True
)
- return ShapeItem(abon=a, sid=info['=.id'].replace('*', ''))
- except KeyError:
- return
+ a.queue_id = info['=.id']
+ return a
+ except ValueError:
+ pass
class QueueManager(TransmitterManager, metaclass=ABCMeta):
@@ -223,50 +224,55 @@ class QueueManager(TransmitterManager, metaclass=ABCMeta):
def add(self, user):
assert isinstance(user, AbonStruct)
- assert isinstance(user.tariff, TariffStruct)
+ if user.tariff is None or not isinstance(user.tariff, TariffStruct):
+ return
return self._exec_cmd(['/queue/simple/add',
- '=name=uid%d' % user.uid,
- #FIXME: тут в разных микротиках или =target-addresses или =target
- '=target=%s' % user.ip.get_str(),
- '=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
- '=queue=MikroBILL_SFQ/MikroBILL_SFQ',
- '=burst-time=1/1'
- ])
+ '=name=uid%d' % user.uid,
+ # FIXME: тут в разных микротиках или =target-addresses или =target
+ '=target=%s' % str(user.ip),
+ '=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
+ '=queue=MikroBILL_SFQ/MikroBILL_SFQ',
+ '=burst-time=1/1'
+ ])
def remove(self, user):
assert isinstance(user, AbonStruct)
q = self.find('uid%d' % user.uid)
if q is not None:
- return self._exec_cmd(['/queue/simple/remove', '=.id=*' + str(q.sid)])
+ return self._exec_cmd(['/queue/simple/remove', '=.id=' + getattr(q, 'queue_id', '')])
def remove_range(self, q_ids):
- names = ['%d' % usr for usr in q_ids]
- return self._exec_cmd(['/queue/simple/remove'] + names)
+ if q_ids is not None and len(q_ids) > 0:
+ return self._exec_cmd(['/queue/simple/remove', '=numbers=' + ','.join(q_ids)])
def update(self, user):
assert isinstance(user, AbonStruct)
+ if user.tariff is None or not isinstance(user.tariff, TariffStruct):
+ return
queue = self.find('uid%d' % user.uid)
if queue is None:
# не нашли запись в шейпере об абоненте, добавим
return self.add(user)
else:
- mk_id = queue.sid
+ mk_id = getattr(queue, 'queue_id', '')
# обновляем шейпер абонента
- return self._exec_cmd(['/queue/simple/set', '=.id=*' + mk_id,
- '=name=uid%d' % user.uid,
- '=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
- #FIXME: тут в разных микротиках или =target-addresses или =target
- '=target=%s' % user.ip.get_str(),
- '=queue=MikroBILL_SFQ/MikroBILL_SFQ',
- '=burst-time=1/1'
- ])
+ return self._exec_cmd(['/queue/simple/set', '=.id=' + mk_id,
+ '=name=uid%d' % user.uid,
+ '=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
+ # FIXME: тут в разных микротиках или =target-addresses или =target
+ '=target=%s' % str(user.ip),
+ '=queue=MikroBILL_SFQ/MikroBILL_SFQ',
+ '=burst-time=1/1'
+ ])
# читаем шейпер, возващаем записи о шейпере
def read_queue_iter(self):
queues = self._exec_cmd_iter(['/queue/simple/print', '=detail'])
for queue in queues:
if queue[0] == '!done': return
- yield self._build_shape_obj(queue[1])
+ sobj = self._build_shape_obj(queue[1])
+ if sobj is not None:
+ yield sobj
# то же что и выше, только получаем только номера в микротике
def read_mikroids_iter(self):
@@ -282,7 +288,7 @@ class QueueManager(TransmitterManager, metaclass=ABCMeta):
self.add(user)
return self.disable(user)
else:
- return self._exec_cmd(['/queue/simple/disable', '=.id=*' + q.sid])
+ return self._exec_cmd(['/queue/simple/disable', '=.id=*' + getattr(q, 'queue_id', '')])
def enable(self, user):
assert isinstance(user, AbonStruct)
@@ -291,7 +297,13 @@ class QueueManager(TransmitterManager, metaclass=ABCMeta):
self.add(user)
self.enable(user)
else:
- return self._exec_cmd(['/queue/simple/enable', '=.id=*' + q.sid])
+ return self._exec_cmd(['/queue/simple/enable', '=.id=*' + getattr(q, 'queue_id', '')])
+
+
+class IpAddressListObj(IpStruct):
+ def __init__(self, ip, mk_id):
+ super(IpAddressListObj, self).__init__(ip)
+ self.mk_id = str(mk_id).replace('*', '')
class IpAddressListManager(TransmitterManager, metaclass=ABCMeta):
@@ -301,7 +313,7 @@ class IpAddressListManager(TransmitterManager, metaclass=ABCMeta):
commands = [
'/ip/firewall/address-list/add',
'=list=%s' % list_name,
- '=address=%s' % ip.get_str()
+ '=address=%s' % str(ip)
]
if type(timeout) is int:
commands.append('=timeout=%d' % timeout)
@@ -311,22 +323,36 @@ class IpAddressListManager(TransmitterManager, metaclass=ABCMeta):
if timeout is not None:
commands = [
'/ip/firewall/address-list/set', '=.id=' + str(mk_id),
- '=timeout=%d' % timeout
+ '=timeout=%d' % timeout
]
return self._exec_cmd(commands)
def remove(self, mk_id):
return self._exec_cmd([
'/ip/firewall/address-list/remove',
- '=.id=*' + str(mk_id)
+ '=.id=*' + str(mk_id).replace('*', '')
])
+ def remove_range(self, items):
+ ids = [ip.mk_id for ip in items if isinstance(ip, IpAddressListObj)]
+ if len(ids) > 0:
+ return self._exec_cmd([
+ '/ip/firewall/address-list/remove',
+ 'numbers=' + ','.join(ids)
+ ])
+
def find(self, ip, list_name):
assert isinstance(ip, IpStruct)
return self._exec_cmd([
'/ip/firewall/address-list/print', 'where',
'?list=%s' % list_name,
- '?address=%s' % ip.get_str()
+ '?address=%s' % str(ip)
+ ])
+
+ def read_ips_iter(self, list_name):
+ return self._exec_cmd([
+ '/ip/firewall/address-list/print', 'where',
+ '?list=%s' % list_name
])
def disable(self, user):
@@ -355,18 +381,18 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
self.add_user(usr)
def remove_user_range(self, users):
- queues = [QueueManager.find(self, 'uid%d' % user.uid) for user in users if isinstance(user, AbonStruct)]
- queue_names = ["uid%d" % queue.sid for queue in queues]
- QueueManager.remove_range(self, queue_names)
+ queue_ids = [usr.queue_id for usr in users if usr is not None]
+ QueueManager.remove_range(self, queue_ids)
ips = [user.ip for user in users if isinstance(user, AbonStruct)]
for ip in ips:
ip_list_entity = IpAddressListManager.find(self, ip, LIST_USERS_ALLOWED)
- if len(ip_list_entity) > 1:
+ if ip_list_entity is not None and len(ip_list_entity) > 1:
IpAddressListManager.remove(self, ip_list_entity[0]['=.id'])
def add_user(self, user, ip_timeout=None):
- assert isinstance(user.tariff, TariffStruct)
assert isinstance(user.ip, IpStruct)
+ if user.tariff is None or not isinstance(user.tariff, TariffStruct):
+ return
QueueManager.add(self, user)
IpAddressListManager.add(self, LIST_USERS_ALLOWED, user.ip, ip_timeout)
# удаляем из списка заблокированных абонентов
@@ -377,12 +403,11 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
def remove_user(self, user):
QueueManager.remove(self, user)
firewall_ip_list_obj = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED)
- if len(firewall_ip_list_obj) > 1:
+ if firewall_ip_list_obj is not None and len(firewall_ip_list_obj) > 1:
IpAddressListManager.remove(self, firewall_ip_list_obj[0]['=.id'])
# обновляем основную инфу абонента
def update_user(self, user, ip_timeout=None):
- assert isinstance(user.tariff, TariffStruct)
assert isinstance(user.ip, IpStruct)
# ищем ip абонента в списке ip
@@ -396,6 +421,13 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
IpAddressListManager.remove(self, find_res[0]['=.id'])
return
+ # если нет услуги то её не должно быть и в nas
+ if user.tariff is None or not isinstance(user.tariff, TariffStruct):
+ queue = QueueManager.find(self, 'uid%d' % user.uid)
+ if queue is not None:
+ QueueManager.remove(self, user)
+ return
+
# если не найден (mikrotik возвращает пустой словарь в списке если ничего нет)
if len(find_res) < 2:
# добавим запись об абоненте
@@ -410,7 +442,7 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
if queue is None:
QueueManager.add(self, user)
return
- if queue.abon != user:
+ if queue != user:
QueueManager.update(self, user)
def ping(self, host, count=10):
@@ -423,14 +455,14 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
interface = r[0]['=interface']
r = self._exec_cmd([
'/ping', '=address=%s' % host, '=arp-ping=yes', '=interval=100ms', '=count=%d' % count,
- '=interface=%s' % interface
+ '=interface=%s' % interface
])
received, sent = int(r[-2:][0]['=received']), int(r[-2:][0]['=sent'])
return received, sent
# приостановливаем обслуживание абонента
def pause_user(self, user):
- pass
+ self.remove_user(user)
# продолжаем обслуживание абонента
def start_user(self, user):
@@ -454,3 +486,9 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
def remove_tariff(self, tid):
pass
+
+ def read_users(self):
+ # shapes is ShapeItem
+ # allowed_ips = IpAddressListManager.read_ips_iter(self, LIST_USERS_ALLOWED)
+ queues = QueueManager.read_queue_iter(self)
+ return queues
diff --git a/agent/netflow/djing_flow.conf b/agent/netflow/djing_flow.conf
deleted file mode 100644
index eccdbfa..0000000
--- a/agent/netflow/djing_flow.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-# Config for djing flow
-
-version = "0.1";
-
-# количество строк на запрос
-mysql_rows_per_request = 65735;
diff --git a/agent/structs.py b/agent/structs.py
index eda9d10..849a296 100644
--- a/agent/structs.py
+++ b/agent/structs.py
@@ -34,9 +34,6 @@ class IpStruct(BaseStruct):
self.__ip = int(dt[0])
return self
- def get_str(self):
- return int2ip(self.__ip)
-
def get_int(self):
return self.__ip
@@ -44,22 +41,32 @@ class IpStruct(BaseStruct):
assert isinstance(other, IpStruct)
return self.__ip == other.__ip
+ def __int__(self):
+ return self.__ip
+
def __str__(self):
return int2ip(self.__ip)
+ def __hash__(self):
+ return hash(self.__ip)
+
# Как обслуживается абонент
class TariffStruct(BaseStruct):
def __init__(self, tariff_id=0, speedIn=None, speedOut=None):
- self.tid = tariff_id
- self.speedIn = speedIn if speedIn is not None else 0.001
- self.speedOut = speedOut if speedOut is not None else 0.001
+ self.tid = int(tariff_id)
+ self.speedIn = float(speedIn if speedIn is not None else 0.001)
+ self.speedOut = float(speedOut if speedOut is not None else 0.001)
def serialize(self):
dt = pack("!Iff", int(self.tid), float(self.speedIn), float(self.speedOut))
return dt
+ # Да, если все значения нулевые
+ def is_empty(self):
+ return self.tid == 0 and self.speedIn == 0.001 and self.speedOut == 0.001
+
def deserialize(self, data, *args):
dt = unpack("!Iff", data)
self.tid = int(dt[0])
@@ -68,7 +75,6 @@ class TariffStruct(BaseStruct):
return self
def __eq__(self, other):
- assert isinstance(other, TariffStruct)
# не сравниваем id, т.к. тарифы с одинаковыми скоростями для NAS одинаковы
# Да и иногда не удобно доставать из nas id тарифы из базы
return self.speedIn == other.speedIn and self.speedOut == other.speedOut
@@ -76,6 +82,11 @@ class TariffStruct(BaseStruct):
def __str__(self):
return "Id=%d, speedIn=%.2f, speedOut=%.2f" % (self.tid, self.speedIn, self.speedOut)
+ # нужно чтоб хеши тарифов In10,Out20 и In20,Out10 были разными
+ # поэтому сначала float->str и потом хеш
+ def __hash__(self):
+ return hash(str(self.speedIn) + str(self.speedOut))
+
# Абонент из базы
class AbonStruct(BaseStruct):
@@ -83,14 +94,15 @@ class AbonStruct(BaseStruct):
def __init__(self, uid=None, ip=None, tariff=None, is_active=True):
self.uid = int(uid)
self.ip = IpStruct(ip)
- assert isinstance(tariff, TariffStruct)
self.tariff = tariff
self.is_active = is_active
def serialize(self):
+ if self.tariff is None:
+ return
assert isinstance(self.tariff, TariffStruct)
assert isinstance(self.ip, IpStruct)
- dt = pack("!LII?", self.uid, self.ip.get_int(), self.tariff.tid, self.is_active)
+ dt = pack("!LII?", self.uid, int(self.ip), self.tariff.tid, self.is_active)
return dt
def deserialize(self, data, tariff=None):
@@ -110,7 +122,10 @@ class AbonStruct(BaseStruct):
return r
def __str__(self):
- return "uid=%d, ip=%s, tariff=%s" % (self.uid, self.ip, self.tariff)
+ return "uid=%d, ip=%s, tariff=%s" % (self.uid, self.ip, self.tariff or '')
+
+ def __hash__(self):
+ return hash(int(self.ip) + hash(self.tariff)) if self.tariff is not None else 0
# Правило шейпинга в фаере, или ещё можно сказать услуга абонента на NAS
diff --git a/bugs.txt b/bugs.txt
index fa0bb2e..e2ba2d8 100644
--- a/bugs.txt
+++ b/bugs.txt
@@ -8,3 +8,7 @@
- Не надо коннектиться к микротику когда не собираемся ничего изменять. А то при сохранении залогинились и вышли без действий
- Не удаляет просроченные услуги если не пингуется NAS
- Надо отменить учёт временной зоны
+!!! Обязательно проверить как отрабатывает на NAS удаление и изменение AbonTariff
+!!! Удалить всё что связано с активацией услуги
+!!! Убрать досрочное завершение услуги
+! Проверить дату завершения услуги
diff --git a/chatbot/locale/ru/LC_MESSAGES/django.po b/chatbot/locale/ru/LC_MESSAGES/django.po
index b5a24c0..e6277c8 100644
--- a/chatbot/locale/ru/LC_MESSAGES/django.po
+++ b/chatbot/locale/ru/LC_MESSAGES/django.po
@@ -20,31 +20,32 @@ msgstr ""
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
-#: chatbot/telebot.py:60
+#: chatbot/telebot.py:61
msgid "Let's get acquainted, what is your name? Write your login from billing."
msgstr "Давай знакомиться, как тебя зовут? Напиши свой логин из биллинга."
-#: chatbot/telebot.py:80
+#: chatbot/telebot.py:81
msgid "I do not know the answer to this yet."
msgstr "Я пока не знаю ответа на это"
-#: chatbot/telebot.py:99
+#: chatbot/telebot.py:100
msgid ""
"You are not found in the database, check that it correctly pointed out its "
"LOGIN. Try again"
msgstr ""
-"Ты не найден в базе, проверь что правильно указал именно свой ЛОГИН. Попробуй ещё"
+"Ты не найден в базе, проверь что правильно указал именно свой ЛОГИН. "
+"Попробуй ещё"
-#: chatbot/telebot.py:122
+#: chatbot/telebot.py:123
msgid "It's not like ip address, try again"
msgstr "Это не похоже на ip адрес, попробуй ещё"
-#: chatbot/telebot.py:125
+#: chatbot/telebot.py:126
#, python-format
msgid "You're '%s', right?"
msgstr "Ты ведь %s ?"
-#: chatbot/telebot.py:135
+#: chatbot/telebot.py:136
#, python-format
msgid "Recipient '%s' does not subscribed on notifications"
msgstr "%s не подписан на оповещения"
diff --git a/chatbot/telebot.py b/chatbot/telebot.py
index 9aecb83..e9c9a56 100755
--- a/chatbot/telebot.py
+++ b/chatbot/telebot.py
@@ -113,7 +113,7 @@ class DjingTelebot(helper.ChatHandler):
# пингуем адрес
def ping(self, ip=None):
if ip is None:
- self._question("Let's ping, write ip. It will be necessary to wait 10 seconds", self.ping)
+ self._question(_("Let's ping, write ip. It will be necessary to wait 10 seconds"), self.ping)
return
try:
socket.inet_aton(ip)
diff --git a/clientsideapp/locale/ru/LC_MESSAGES/django.po b/clientsideapp/locale/ru/LC_MESSAGES/django.po
index 6b08e8a..9fcf3b2 100644
--- a/clientsideapp/locale/ru/LC_MESSAGES/django.po
+++ b/clientsideapp/locale/ru/LC_MESSAGES/django.po
@@ -68,81 +68,15 @@ msgstr "Заказать услугу"
msgid "Are you sure you want to order the service?"
msgstr "Вы уверены что хотите заказать услугу?"
-#: clientsideapp/templates/clientsideapp/modal_service_buy.html:10
-#, python-format
-msgid ""
-"Your current service %(current_service.title)s\n"
-"for the %(amount)s rub."
-msgstr ""
-"Ваша текущая услуга %(current_service.title)s\n"
-"за %(amount)s руб."
-#: clientsideapp/templates/clientsideapp/modal_service_buy.html:13
-msgid ""
-"You do not have an active service for the use of resources required service "
-"purchase from the selection below. \n"
-"And if you have already booked then just activate the service from the list "
-"ordered."
-msgstr ""
-"У вас нет активной услуги, для использования ресурсов приобретите нужную "
-"услугу из представленных ниже. \n"
-"А если уже заказали то просто активируйте услугу из списка заказанных."
-
-#: clientsideapp/templates/clientsideapp/modal_service_buy.html:21
-#, python-format
-msgid ""
-"Inbound speed: %(speedIn)s MBit/s \n"
-"Outgoing speed: %(speedOut)s MBit/s \n"
-"Cost: %(amount)s rubles."
-msgstr ""
-"Входящая скорость: %(speedIn)s MBit/s \n"
-"Исходящая скорость: %(speedOut)s MBit/s \n"
-"Стоимость: %(amount)s руб."
-
-#: clientsideapp/templates/clientsideapp/modal_service_buy.html:27
+#: clientsideapp/templates/clientsideapp/modal_service_buy.html:28
msgid "Pick"
msgstr "Заказать"
-#: clientsideapp/templates/clientsideapp/modal_service_buy.html:29
-#: clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html:24
+#: clientsideapp/templates/clientsideapp/modal_service_buy.html:30
msgid "Close"
msgstr "Закрыть"
-#: clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html:5
-msgid "Unsubscribe from service"
-msgstr "Отписаться от услуги"
-
-#: clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html:8
-msgid "Are you sure you want to unsubscribe from the service?"
-msgstr "Вы уверены что хотите отписаться от услуги?"
-
-#: clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html:14
-#, fuzzy, python-format
-#| msgid ""
-#| "Inbound speed: %(service.speedIn)s MBit/s \n"
-#| "Outgoing speed: %(service.speedOut)s MBit/s \n"
-#| "Cost: %(service.amount)s rubles."
-msgid ""
-"Inbound speed: %(service.speedIn)s MBit/s Outgoing speed: "
-"%(service.speedOut)s MBit/s"
-msgstr ""
-"Входящая скорость: %(service.speedIn)s MBit/s \n"
-"Исходящая скорость: %(service.speedOut)s MBit/s"
-
-#: clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html:16
-msgid ""
-"When you unsubscribe from the service, it just will remove it from the queue "
-"inclusions your services. \n"
-"Your funds will not be affected, the money will not go away."
-msgstr ""
-"Когда вы отпишитесь от услуги, это просто уберёт её из очереди включений "
-"ваших услуг. \n"
-"Ваши средства не буду затронуты, деньги не уйдут."
-
-#: clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html:22
-msgid "Unsubscribe"
-msgstr "Отписаться"
-
#: clientsideapp/templates/clientsideapp/pays.html:6
msgid "conducted payments"
msgstr "Проведённые платежи"
@@ -162,3 +96,44 @@ msgstr "Комментарий"
#: clientsideapp/templates/clientsideapp/pays.html:25
msgid "You have not spent payments"
msgstr "У вас нет проведённых платежей"
+
+#: clientsideapp/views.py:53
+#, python-format
+msgid "Buy the service via user side, service '%s'"
+msgstr "Покупка тарифного плана через личный кабинет, тариф '%s'"
+
+#: clientsideapp/views.py:82
+#, python-format
+msgid "Service '%s' has been finished"
+msgstr "Услуга '%s' успешно завершена"
+
+#: clientsideapp/views.py:87
+#, python-format
+msgid "Early terminated service '%s' via client side"
+msgstr "Досрочное завершение услуги '%s' из личного кабинета"
+
+#: clientsideapp/views.py:90 clientsideapp/views.py:119
+#: clientsideapp/views.py:147
+msgid "Act is not confirmed"
+msgstr "Действие не подтверждено"
+
+#: clientsideapp/views.py:103 clientsideapp/views.py:130
+msgid "Temporary network bug"
+msgstr "Временные неполадки в сети"
+
+#: clientsideapp/views.py:126
+msgid "The service was not found"
+msgstr "Указанная подписка на услугу не найдена"
+
+#: clientsideapp/views.py:145
+#, python-format
+msgid "The service '%s' wan successfully activated"
+msgstr "Услуга '%s' успешно подключена"
+
+#: clientsideapp/views.py:181
+msgid "Are you not sure that you want buy the service?"
+msgstr "Вы не уверены что хотите оплатить долг?"
+
+#: clientsideapp/views.py:183
+msgid "Your account have not enough money"
+msgstr "Недостаточно средств на счету"
diff --git a/clientsideapp/templates/clientsideapp/ext.html b/clientsideapp/templates/clientsideapp/ext.html
index 5e2b2bd..b19ef15 100644
--- a/clientsideapp/templates/clientsideapp/ext.html
+++ b/clientsideapp/templates/clientsideapp/ext.html
@@ -11,7 +11,7 @@
-/head>
+
@@ -71,13 +71,11 @@
Ваш балланс {{ subscriber.ballance }} руб.
-
-
+
-
{% if request.user.is_staff %}
diff --git a/clientsideapp/templates/clientsideapp/index.html b/clientsideapp/templates/clientsideapp/index.html
index 372425b..a0ff0b2 100644
--- a/clientsideapp/templates/clientsideapp/index.html
+++ b/clientsideapp/templates/clientsideapp/index.html
@@ -9,8 +9,7 @@
Телефоны: +79788328885, +79788318999
Адрес: пос. Нижнегорский, ул. Победы 38. 2й этаж старого дома быта, возле рынка
-
+
diff --git a/clientsideapp/templates/clientsideapp/modal_activate_service.html b/clientsideapp/templates/clientsideapp/modal_activate_service.html
deleted file mode 100644
index 545fb76..0000000
--- a/clientsideapp/templates/clientsideapp/modal_activate_service.html
+++ /dev/null
@@ -1,28 +0,0 @@
-
diff --git a/clientsideapp/templates/clientsideapp/modal_complete_service.html b/clientsideapp/templates/clientsideapp/modal_complete_service.html
deleted file mode 100644
index cb4ca76..0000000
--- a/clientsideapp/templates/clientsideapp/modal_complete_service.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
diff --git a/clientsideapp/templates/clientsideapp/modal_service_buy.html b/clientsideapp/templates/clientsideapp/modal_service_buy.html
index 433a1a6..93d6d7d 100644
--- a/clientsideapp/templates/clientsideapp/modal_service_buy.html
+++ b/clientsideapp/templates/clientsideapp/modal_service_buy.html
@@ -6,13 +6,7 @@
{% trans 'Are you sure you want to order the service?' %}
- {% if current_service %}
- {% blocktrans with amount=current_service.amount %}Your current service {{ current_service.title }}
-for the {{ amount }} rub.{% endblocktrans %}
- {% else %}
- {% blocktrans %}You do not have an active service for the use of resources required service purchase from the selection below.
-And if you have already booked then just activate the service from the list ordered.{% endblocktrans %}
- {% endif %}
+ Будте внимательны, после заказа услуги с вашего счёта снимутся средства, и вы сможете пользоваться купленной услугой.
{{ service.title }}
@@ -25,7 +19,7 @@ Cost: {{ amount }} rubles.{% endblocktrans %}-->
diff --git a/clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html b/clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html
deleted file mode 100644
index e8250c0..0000000
--- a/clientsideapp/templates/clientsideapp/modal_unsubscribe_service.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{% load i18n %}
-
diff --git a/clientsideapp/templates/clientsideapp/services.html b/clientsideapp/templates/clientsideapp/services.html
index b900a28..9646d95 100644
--- a/clientsideapp/templates/clientsideapp/services.html
+++ b/clientsideapp/templates/clientsideapp/services.html
@@ -1,81 +1,72 @@
{% extends 'clientsideapp/ext.html' %}
+{% load i18n %}
{% block client_main %}
|