Browse Source

little bit refactoring

devel
bashmak 8 years ago
parent
commit
a768482912
  1. 2
      abonapp/models.py
  2. 2
      abonapp/templates/abonapp/peoples.html
  3. 17
      abonapp/views.py
  4. 2
      agent/commands/dhcp.py
  5. 29
      devapp/base_intr.py
  6. 81
      devapp/dev_types.py
  7. 4
      devapp/models.py
  8. 2
      devapp/views.py
  9. 18
      djing/lib/__init__.py
  10. 10
      djing/lib/decorators.py
  11. 19
      docs/dev.md
  12. 2
      ip_pool/templates/ip_pool/net_add.html
  13. 4
      mapapp/urls.py
  14. 34
      mapapp/views.py
  15. 20
      tariff_app/base_intr.py
  16. 30
      tariff_app/custom_tariffs.py

2
abonapp/models.py

@ -162,7 +162,7 @@ class Abon(BaseAccount):
Return icon list of set flags from self.markers Return icon list of set flags from self.markers
:return: ['m-icon-donkey', 'm-icon-tv', ...] :return: ['m-icon-donkey', 'm-icon-tv', ...]
""" """
return ["m-%s" % name for name, state in self.markers if state]
return tuple("m-%s" % name for name, state in self.markers if state)
def is_markers_empty(self): def is_markers_empty(self):
return int(self.markers) == 0 return int(self.markers) == 0

2
abonapp/templates/abonapp/peoples.html

@ -10,6 +10,8 @@
</ol> </ol>
{% endblock %} {% endblock %}
{% block page-header %}{{ group.title }}{% endblock %}
{% block main %} {% block main %}
<div class="row"> <div class="row">
<div class="col-lg-10 col-md-8"> <div class="col-lg-10 col-md-8">

17
abonapp/views.py

@ -30,16 +30,11 @@ from guardian.shortcuts import get_objects_for_user, assign_perm
from guardian.decorators import permission_required_or_403 as permission_required from guardian.decorators import permission_required_or_403 as permission_required
from djing import ping from djing import ping
from djing import lib from djing import lib
from djing.global_base_views import OrderingMixin, BaseListWithFiltering, SecureApiView
class BaseAbonListView(OrderingMixin, BaseListWithFiltering):
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
http_method_names = ('get',)
from djing.global_base_views import BaseOrderedFilteringList, SecureApiView
@method_decorator((login_required, lib.decorators.only_admins), name='dispatch') @method_decorator((login_required, lib.decorators.only_admins), name='dispatch')
class PeoplesListView(BaseAbonListView):
class PeoplesListView(BaseOrderedFilteringList):
context_object_name = 'peoples' context_object_name = 'peoples'
template_name = 'abonapp/peoples.html' template_name = 'abonapp/peoples.html'
@ -84,7 +79,7 @@ class PeoplesListView(BaseAbonListView):
@method_decorator((login_required, lib.decorators.only_admins), name='dispatch') @method_decorator((login_required, lib.decorators.only_admins), name='dispatch')
class GroupListView(BaseAbonListView):
class GroupListView(BaseOrderedFilteringList):
context_object_name = 'groups' context_object_name = 'groups'
template_name = 'abonapp/group_list.html' template_name = 'abonapp/group_list.html'
queryset = Group.objects.annotate(usercount=Count('abon')) queryset = Group.objects.annotate(usercount=Count('abon'))
@ -212,7 +207,7 @@ def abonamount(request, gid, uname):
@method_decorator((login_required, lib.decorators.only_admins), name='dispatch') @method_decorator((login_required, lib.decorators.only_admins), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch') @method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
class DebtsListView(BaseAbonListView):
class DebtsListView(BaseOrderedFilteringList):
context_object_name = 'invoices' context_object_name = 'invoices'
template_name = 'abonapp/invoiceForPayment.html' template_name = 'abonapp/invoiceForPayment.html'
@ -230,7 +225,7 @@ class DebtsListView(BaseAbonListView):
@method_decorator((login_required, lib.decorators.only_admins), name='dispatch') @method_decorator((login_required, lib.decorators.only_admins), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch') @method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
class PayHistoryListView(BaseAbonListView):
class PayHistoryListView(BaseOrderedFilteringList):
context_object_name = 'pay_history' context_object_name = 'pay_history'
template_name = 'abonapp/payHistory.html' template_name = 'abonapp/payHistory.html'
@ -756,7 +751,7 @@ def abon_ping(request):
@method_decorator((login_required, lib.decorators.only_admins,), name='dispatch') @method_decorator((login_required, lib.decorators.only_admins,), name='dispatch')
class DialsListView(BaseAbonListView):
class DialsListView(BaseOrderedFilteringList):
context_object_name = 'logs' context_object_name = 'logs'
template_name = 'abonapp/dial_log.html' template_name = 'abonapp/dial_log.html'

2
agent/commands/dhcp.py

@ -9,7 +9,7 @@ def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: i
dev = Device.objects.get(mac_addr=switch_mac) dev = Device.objects.get(mac_addr=switch_mac)
mngr_class = dev.get_manager_klass() mngr_class = dev.get_manager_klass()
if mngr_class.is_use_device_port():
if mngr_class.get_is_use_device_port():
abon = Abon.objects.get(dev_port__device=dev, abon = Abon.objects.get(dev_port__device=dev,
dev_port__num=switch_port, dev_port__num=switch_port,
device=dev) device=dev)

29
devapp/base_intr.py

@ -5,15 +5,13 @@ from easysnmp import Session
from django.utils.translation import gettext from django.utils.translation import gettext
from djing.lib.decorators import abstract_static_method
ListOrError = Union[ ListOrError = Union[
Iterable, Iterable,
Union[Exception, Iterable] Union[Exception, Iterable]
] ]
class DeviceImplementationError(Exception):
class DeviceImplementationError(NotImplementedError):
pass pass
@ -25,10 +23,15 @@ class DevBase(object, metaclass=ABCMeta):
def __init__(self, dev_instance=None): def __init__(self, dev_instance=None):
self.db_instance = dev_instance self.db_instance = dev_instance
@abstract_static_method
def description() -> AnyStr:
@property
@abstractmethod
def description(self) -> AnyStr:
pass pass
@classmethod
def get_description(cls):
return cls.description
@abstractmethod @abstractmethod
def reboot(self): def reboot(self):
pass pass
@ -49,23 +52,29 @@ class DevBase(object, metaclass=ABCMeta):
def get_template_name(self) -> AnyStr: def get_template_name(self) -> AnyStr:
"""Return path to html template for device""" """Return path to html template for device"""
@property
@abstractmethod @abstractmethod
def has_attachable_to_subscriber(self) -> bool: def has_attachable_to_subscriber(self) -> bool:
"""Can connect device to subscriber""" """Can connect device to subscriber"""
@abstract_static_method
def is_use_device_port() -> bool:
@property
@abstractmethod
def is_use_device_port(self) -> bool:
"""True if used device port while opt82 authorization""" """True if used device port while opt82 authorization"""
# fixme: only that is abstract static
@abstract_static_method
def validate_extra_snmp_info(v: str) -> None:
@classmethod
def get_is_use_device_port(cls) -> bool:
return cls.is_use_device_port
@classmethod
def validate_extra_snmp_info(cls, v: str) -> None:
""" """
Validate extra snmp field for each device. Validate extra snmp field for each device.
If validation failed then raise en exception from djing.lib.tln.ValidationError If validation failed then raise en exception from djing.lib.tln.ValidationError
with description of error. with description of error.
:param v: String value for validate :param v: String value for validate
""" """
raise NotImplementedError
@abstractmethod @abstractmethod
def register_device(self, extra_data: Dict): def register_device(self, extra_data: Dict):

81
devapp/dev_types.py

@ -60,14 +60,14 @@ class DLinkPort(BasePort):
class DLinkDevice(DevBase, SNMPBaseWorker): class DLinkDevice(DevBase, SNMPBaseWorker):
has_attachable_to_subscriber = True
description = _('DLink switch')
is_use_device_port = True
def __init__(self, dev_instance): def __init__(self, dev_instance):
DevBase.__init__(self, dev_instance) DevBase.__init__(self, dev_instance)
SNMPBaseWorker.__init__(self, dev_instance.ip_address, dev_instance.man_passw, 2) SNMPBaseWorker.__init__(self, dev_instance.ip_address, dev_instance.man_passw, 2)
@staticmethod
def description():
return _('DLink switch')
def reboot(self): def reboot(self):
return self.get_item('.1.3.6.1.4.1.2021.8.1.101.1') return self.get_item('.1.3.6.1.4.1.2021.8.1.101.1')
@ -103,15 +103,8 @@ class DLinkDevice(DevBase, SNMPBaseWorker):
def get_template_name(self): def get_template_name(self):
return 'ports.html' return 'ports.html'
def has_attachable_to_subscriber(self) -> bool:
return True
@staticmethod
def is_use_device_port():
return True
@staticmethod
def validate_extra_snmp_info(v: str) -> None:
@classmethod
def validate_extra_snmp_info(cls, v: str) -> None:
# Dlink has no require snmp info # Dlink has no require snmp info
pass pass
@ -142,14 +135,14 @@ class ONUdev(BasePort):
class OLTDevice(DevBase, SNMPBaseWorker): class OLTDevice(DevBase, SNMPBaseWorker):
has_attachable_to_subscriber = False
description = _('PON OLT')
is_use_device_port = False
def __init__(self, dev_instance): def __init__(self, dev_instance):
DevBase.__init__(self, dev_instance) DevBase.__init__(self, dev_instance)
SNMPBaseWorker.__init__(self, dev_instance.ip_address, dev_instance.man_passw, 2) SNMPBaseWorker.__init__(self, dev_instance.ip_address, dev_instance.man_passw, 2)
@staticmethod
def description():
return gettext('PON OLT')
def reboot(self): def reboot(self):
pass pass
@ -187,15 +180,8 @@ class OLTDevice(DevBase, SNMPBaseWorker):
def get_template_name(self): def get_template_name(self):
return 'olt.html' return 'olt.html'
def has_attachable_to_subscriber(self) -> bool:
return False
@staticmethod
def is_use_device_port():
return False
@staticmethod
def validate_extra_snmp_info(v: str) -> None:
@classmethod
def validate_extra_snmp_info(cls, v: str) -> None:
# Olt has no require snmp info # Olt has no require snmp info
pass pass
@ -208,6 +194,10 @@ class OLTDevice(DevBase, SNMPBaseWorker):
class OnuDevice(DevBase, SNMPBaseWorker): class OnuDevice(DevBase, SNMPBaseWorker):
has_attachable_to_subscriber = True
description = _('PON ONU')
is_use_device_port = False
def __init__(self, dev_instance): def __init__(self, dev_instance):
DevBase.__init__(self, dev_instance) DevBase.__init__(self, dev_instance)
dev_ip_addr = None dev_ip_addr = None
@ -223,15 +213,11 @@ class OnuDevice(DevBase, SNMPBaseWorker):
)) ))
SNMPBaseWorker.__init__(self, dev_ip_addr, dev_instance.man_passw, 2) SNMPBaseWorker.__init__(self, dev_ip_addr, dev_instance.man_passw, 2)
@staticmethod
def description() -> AnyStr:
return gettext('PON ONU')
def reboot(self): def reboot(self):
pass pass
def get_ports(self) -> ListOrError: def get_ports(self) -> ListOrError:
return []
return ()
def get_device_name(self): def get_device_name(self):
pass pass
@ -242,13 +228,6 @@ class OnuDevice(DevBase, SNMPBaseWorker):
def get_template_name(self): def get_template_name(self):
return "onu.html" return "onu.html"
def has_attachable_to_subscriber(self) -> bool:
return True
@staticmethod
def is_use_device_port():
return False
def get_details(self): def get_details(self):
if self.db_instance is None: if self.db_instance is None:
return return
@ -274,7 +253,7 @@ class OnuDevice(DevBase, SNMPBaseWorker):
return {'err': "%s: %s" % (_('ONU not connected'), e)} return {'err': "%s: %s" % (_('ONU not connected'), e)}
@staticmethod @staticmethod
def validate_extra_snmp_info(v: str) -> None:
def validate_extra_snmp_info(cls, v: str) -> None:
# DBCOM Onu have en integer snmp port # DBCOM Onu have en integer snmp port
try: try:
int(v) int(v)
@ -330,9 +309,8 @@ class EltexPort(BasePort):
class EltexSwitch(DLinkDevice): class EltexSwitch(DLinkDevice):
@staticmethod
def description():
return _('Eltex switch')
description = _('Eltex switch')
is_use_device_port = False
def get_ports(self) -> ListOrError: def get_ports(self) -> ListOrError:
res = [] res = []
@ -355,13 +333,6 @@ class EltexSwitch(DLinkDevice):
tm = RuTimedelta(timedelta(seconds=uptimestamp / 100)) or RuTimedelta(timedelta()) tm = RuTimedelta(timedelta(seconds=uptimestamp / 100)) or RuTimedelta(timedelta())
return tm return tm
def has_attachable_to_subscriber(self) -> bool:
return True
@staticmethod
def is_use_device_port():
return False
def monitoring_template(self, *args, **kwargs) -> Optional[str]: def monitoring_template(self, *args, **kwargs) -> Optional[str]:
device = self.db_instance device = self.db_instance
return plain_ip_device_mon_template(device) return plain_ip_device_mon_template(device)
@ -378,9 +349,7 @@ def conv_signal(lvl: int) -> float:
class Olt_ZTE_C320(OLTDevice): class Olt_ZTE_C320(OLTDevice):
@staticmethod
def description():
return gettext('OLT ZTE C320')
description = _('OLT ZTE C320')
def get_fibers(self): def get_fibers(self):
fibers = ({ fibers = ({
@ -443,9 +412,7 @@ class Olt_ZTE_C320(OLTDevice):
class ZteOnuDevice(OnuDevice): class ZteOnuDevice(OnuDevice):
@staticmethod
def description():
return _('ZTE PON ONU')
description = _('ZTE PON ONU')
def get_details(self) -> Optional[Dict]: def get_details(self) -> Optional[Dict]:
if self.db_instance is None: if self.db_instance is None:
@ -472,8 +439,8 @@ class ZteOnuDevice(OnuDevice):
def get_template_name(self): def get_template_name(self):
return 'onu_for_zte.html' return 'onu_for_zte.html'
@staticmethod
def validate_extra_snmp_info(v: str) -> None:
@classmethod
def validate_extra_snmp_info(cls, v: str) -> None:
# for example 268501760.5 # for example 268501760.5
try: try:
fiber_num, onu_port = v.split('.') fiber_num, onu_port = v.split('.')

4
devapp/models.py

@ -90,8 +90,8 @@ class Device(models.Model):
# Can attach device to subscriber in subscriber page # Can attach device to subscriber in subscriber page
def has_attachable_to_subscriber(self) -> bool: def has_attachable_to_subscriber(self) -> bool:
mngr = self.get_manager_object()
return mngr.has_attachable_to_subscriber()
mngr = self.get_manager_klass()
return mngr.has_attachable_to_subscriber
def __str__(self): def __str__(self):
return "%s: (%s) %s %s" % (self.comment, self.get_devtype_display(), self.ip_address or '', self.mac_addr or '') return "%s: (%s) %s %s" % (self.comment, self.get_devtype_display(), self.ip_address or '', self.mac_addr or '')

2
devapp/views.py

@ -650,7 +650,7 @@ class OnDeviceMonitoringEvent(global_base_views.SecureApiView):
recipients = UserProfile.objects.get_profiles_by_group(device_down.group.pk) recipients = UserProfile.objects.get_profiles_by_group(device_down.group.pk)
names = list() names = list()
for recipient in recipients:
for recipient in recipients.iterator():
send_notify( send_notify(
msg_text=gettext(notify_text) % { msg_text=gettext(notify_text) % {
'device_name': "%s(%s) %s" % ( 'device_name': "%s(%s) %s" % (

18
djing/lib/__init__.py

@ -38,24 +38,16 @@ def safe_int(i):
# классы передавать для того чтоб по значению кода из базы понять какой класс нужно взять для нужной функциональности. # классы передавать для того чтоб по значению кода из базы понять какой класс нужно взять для нужной функциональности.
# Например по коду в базе вам нужно определять как считать тариф абонента, что реализовано в возвращаемом классе. # Например по коду в базе вам нужно определять как считать тариф абонента, что реализовано в возвращаемом классе.
class MyChoicesAdapter(Iterator): class MyChoicesAdapter(Iterator):
chs = tuple()
current_index = 0
_max_index = 0
_chs = None
# На вход принимает кортеж кортежей, вложенный из 2х элементов: кода и класса, как: TARIFF_CHOICES # На вход принимает кортеж кортежей, вложенный из 2х элементов: кода и класса, как: TARIFF_CHOICES
def __init__(self, choices): def __init__(self, choices):
self._max_index = len(choices)
self.chs = choices
self._chs = iter(choices)
def __next__(self): def __next__(self):
if self.current_index >= self._max_index:
raise StopIteration
else:
e = self.chs
ci = self.current_index
res = e[ci][0], e[ci][1].description()
self.current_index += 1
return res
obj = next(self._chs)
choice_code, choice_class = obj
return choice_code, choice_class.get_description()
# Russian localized timedelta # Russian localized timedelta

10
djing/lib/decorators.py

@ -55,13 +55,3 @@ def hash_auth_view(fn):
else: else:
return HttpResponseForbidden('Access Denied') return HttpResponseForbidden('Access Denied')
return wrapped return wrapped
class abstract_static_method(staticmethod):
__slots__ = ()
def __init__(self, func):
super(abstract_static_method, self).__init__(func)
func.__isabstractmethod__ = True
__isabstractmethod__ = True

19
docs/dev.md

@ -47,10 +47,9 @@ class EltexPort(BasePort):
Теперь реализация для свича: Теперь реализация для свича:
```python ```python
class EltexSwitch(DLinkDevice): class EltexSwitch(DLinkDevice):
@staticmethod
def description():
return _('Eltex switch')
has_attachable_to_subscriber = False
description = _('Eltex switch')
is_use_device_port = False
def get_ports(self): def get_ports(self):
#nams = self.get_list('.1.3.6.1.4.1.171.10.134.2.1.1.100.2.1.3') #nams = self.get_list('.1.3.6.1.4.1.171.10.134.2.1.1.100.2.1.3')
@ -77,14 +76,8 @@ class EltexSwitch(DLinkDevice):
tm = RuTimedelta(timedelta(seconds=uptimestamp/100)) or RuTimedelta(timedelta()) tm = RuTimedelta(timedelta(seconds=uptimestamp/100)) or RuTimedelta(timedelta())
return tm return tm
def has_attachable_to_subscriber(self) -> bool:
return False
@staticmethod
def is_use_device_port():
return False
``` ```
Метод **@description** Просто отображает человекопонятное название вашего устройства в биллинге.
Свойство **@description** Просто отображает человекопонятное название вашего устройства в биллинге.
Заметьте что строка на английском и заключена в процедуру **_** (это ugettext_lazy, см. в импорте вверху файла), Заметьте что строка на английском и заключена в процедуру **_** (это ugettext_lazy, см. в импорте вверху файла),
это локализация для текущего языка. Про локализацию можно почитать в соответствующем разделе [django translation](https://docs.djangoproject.com/en/1.11/topics/i18n/translation/). это локализация для текущего языка. Про локализацию можно почитать в соответствующем разделе [django translation](https://docs.djangoproject.com/en/1.11/topics/i18n/translation/).
@ -98,11 +91,11 @@ class EltexSwitch(DLinkDevice):
Метод **@uptime**, понятно что возвращает, укажите нужный OID. Вернётся тип *RuTimedelta*, это переопределённый тип **timedelta**, я его реализовал Метод **@uptime**, понятно что возвращает, укажите нужный OID. Вернётся тип *RuTimedelta*, это переопределённый тип **timedelta**, я его реализовал
для локализации временного промежутка на русский. для локализации временного промежутка на русский.
Метод **@has_attachable_to_subscriber** возвращает правду если это устройство можно привязать к абоненту.
Свойство **@has_attachable_to_subscriber** возвращает правду если это устройство можно привязать к абоненту.
Например у Dlink стоит True потому что Dlink стоит во многих местах на доступе, и его порты принадлежат Например у Dlink стоит True потому что Dlink стоит во многих местах на доступе, и его порты принадлежат
абонентам при авторизации. абонентам при авторизации.
Статический метод **@is_use_device_port** используется в DHCP чтоб понять что мы используем для привязки к абоненту всё устройство или
Свойство **@is_use_device_port** используется в DHCP чтоб понять что мы используем для привязки к абоненту всё устройство или
только порт устройства. Например, если у устройства только 1 порт абонента (PON ONU), и мы привязываем этого абонента ко всему устройству только порт устройства. Например, если у устройства только 1 порт абонента (PON ONU), и мы привязываем этого абонента ко всему устройству
а не к порту, то нужно вернуть False, На обычных свичах где мы авторизуем абонента на порту возвращаем True. а не к порту, то нужно вернуть False, На обычных свичах где мы авторизуем абонента на порту возвращаем True.

2
ip_pool/templates/ip_pool/net_add.html

@ -11,6 +11,8 @@
</ol> </ol>
{% endblock %} {% endblock %}
{% block page-header %}{% trans 'Add new subnet' %}{% endblock %}
{% block main %} {% block main %}
<form action="{% url 'ip_pool:net_add' %}" method="post">{% csrf_token %} <form action="{% url 'ip_pool:net_add' %}" method="post">{% csrf_token %}
<div class="panel panel-default"> <div class="panel panel-default">

4
mapapp/urls.py

@ -7,8 +7,8 @@ app_name = 'mapapp'
urlpatterns = [ urlpatterns = [
url(r'^$', views.home, name='home'), url(r'^$', views.home, name='home'),
url(r'^options$', views.OptionsListView.as_view(), name='options'), url(r'^options$', views.OptionsListView.as_view(), name='options'),
url(r'^options/add$', views.dot, name='add_dot'),
url(r'^options/(?P<did>\d+)/edit$', views.dot, name='edit_dot'),
url(r'^options/add$', views.dot_edit, name='add_dot'),
url(r'^options/(?P<did>\d+)/edit$', views.dot_edit, name='edit_dot'),
url(r'^options/(?P<did>\d+)/remove$', views.remove, name='remove_dot'), url(r'^options/(?P<did>\d+)/remove$', views.remove, name='remove_dot'),
url(r'^options/(?P<did>\d+)/add_dev$', views.add_dev, name='add_dev'), url(r'^options/(?P<did>\d+)/add_dev$', views.add_dev, name='add_dev'),
url(r'^preload_devices$', views.preload_devices, name='preload_devices'), url(r'^preload_devices$', views.preload_devices, name='preload_devices'),

34
mapapp/views.py

@ -31,8 +31,8 @@ def home(request):
dots = Dot.objects.all() dots = Dot.objects.all()
groups = Group.objects.all() groups = Group.objects.all()
return render(request, 'maps/ya_index.html', { return render(request, 'maps/ya_index.html', {
'dots': dots,
'groups': groups
'dots': dots.iterator(),
'groups': groups.iterator()
}) })
@ -49,7 +49,7 @@ class OptionsListView(BaseListView):
@login_required @login_required
def dot(request, did=0):
def dot_edit(request, did=0):
if not request.user.is_superuser: if not request.user.is_superuser:
return redirect('/') return redirect('/')
try: try:
@ -101,9 +101,9 @@ def remove(request, did):
def get_dots(request): def get_dots(request):
if not request.user.is_superuser: if not request.user.is_superuser:
return HttpResponseForbidden('you have not super user') return HttpResponseForbidden('you have not super user')
dots = Dot.objects.prefetch_related('devices').annotate(devcount=Count('devices')).defer('attachment')
dots = Dot.objects.prefetch_related('devices').annotate(devcount=Count('devices')).defer('attachment').iterator()
def fill_dev(dev):
def fill_dev(dev: Device):
return { return {
'status': dev.status, 'status': dev.status,
'comment': dev.comment 'comment': dev.comment
@ -169,15 +169,15 @@ def modal_add_dot(request):
def preload_devices(request): def preload_devices(request):
if not request.user.is_superuser: if not request.user.is_superuser:
return HttpResponseForbidden('you have not super user') return HttpResponseForbidden('you have not super user')
grp = request.GET.get('grp')
dot = request.GET.get('dot')
all_devices = Device.objects.filter(group__id=grp)
dot_devices = Device.objects.filter(dot__id=dot)
dot_devices_ids = [dev.pk for dev in dot_devices]
grp_id = request.GET.get('grp')
dot_id = request.GET.get('dot')
all_devices = Device.objects.filter(group__id=grp_id)
dot_devices = Device.objects.filter(dot__id=dot_id)
dot_devices_ids = tuple(dev.pk for dev in dot_devices.iterator())
del dot_devices
ret = render_to_text('maps/preload_devices_tmpl.html', { ret = render_to_text('maps/preload_devices_tmpl.html', {
'all_devices': all_devices,
'all_devices': all_devices.iterator(),
'dot_devices_ids': dot_devices_ids 'dot_devices_ids': dot_devices_ids
}) })
return HttpResponse(ret, content_type='text/html') return HttpResponse(ret, content_type='text/html')
@ -195,7 +195,7 @@ def dot_tooltip(request):
except Dot.DoesNotExist: except Dot.DoesNotExist:
pass pass
return render_to_text('maps/map_tooltip.html', { return render_to_text('maps/map_tooltip.html', {
'devs': devs,
'devs': devs.iterator(),
'dot': dot 'dot': dot
}) })
@ -213,8 +213,8 @@ def add_dev(request, did):
selected_user_group = safe_int(request.POST.get('selected_user_group')) selected_user_group = safe_int(request.POST.get('selected_user_group'))
existing_devs = Device.objects.filter(group__id=selected_user_group or param_user_group) existing_devs = Device.objects.filter(group__id=selected_user_group or param_user_group)
if existing_devs.count() > 0:
dot.devices.remove(*[dev.pk for dev in existing_devs])
if existing_devs.exists():
dot.devices.remove(*(dev.pk for dev in existing_devs.iterator()))
dot.devices.add(*selected_devs) dot.devices.add(*selected_devs)
url = resolve_url('mapapp:add_dev', did=dot.pk) url = resolve_url('mapapp:add_dev', did=dot.pk)
@ -222,9 +222,9 @@ def add_dev(request, did):
else: else:
existing_devs = Device.objects.filter(group=param_user_group) existing_devs = Device.objects.filter(group=param_user_group)
return render(request, 'maps/add_device.html', { return render(request, 'maps/add_device.html', {
'groups': groups,
'groups': groups.iterator(),
'dot': dot, 'dot': dot,
'existing_devs': existing_devs,
'existing_devs': existing_devs.iterator(),
'grp': param_user_group, 'grp': param_user_group,
'dot_devices_ids': [dev.pk for dev in Device.objects.filter(dot=dot)] 'dot_devices_ids': [dev.pk for dev in Device.objects.filter(dot=dot)]
}) })

20
tariff_app/base_intr.py

@ -14,13 +14,17 @@ class TariffBase(metaclass=ABCMeta):
"""Calculate deadline date""" """Calculate deadline date"""
raise NotImplementedError raise NotImplementedError
@staticmethod
def description() -> AnyStr:
@property
@abstractmethod
def description(self) -> AnyStr:
""" """
Usage in djing.lib.MyChoicesAdapter for choices fields. Usage in djing.lib.MyChoicesAdapter for choices fields.
:return: human readable description :return: human readable description
""" """
raise NotImplementedError
@classmethod
def get_description(cls):
return cls.description
@staticmethod @staticmethod
def manage_access(abon) -> bool: def manage_access(abon) -> bool:
@ -51,8 +55,12 @@ class PeriodicPayCalcBase(metaclass=ABCMeta):
""" """
raise NotImplementedError raise NotImplementedError
@staticmethod
def description() -> AnyStr:
@property
@abstractmethod
def description(self) -> AnyStr:
"""Return text description. """Return text description.
Uses in djing.lib.MyChoicesAdapter for CHOICES fields""" Uses in djing.lib.MyChoicesAdapter for CHOICES fields"""
raise NotImplementedError
@classmethod
def get_description(cls):
return cls.description

30
tariff_app/custom_tariffs.py

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from datetime import timedelta, datetime from datetime import timedelta, datetime
from typing import AnyStr
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
@ -11,6 +10,8 @@ from random import uniform
class TariffDefault(TariffBase): class TariffDefault(TariffBase):
description = _('Base calculate functionality')
def __init__(self, abon_tariff): def __init__(self, abon_tariff):
# assert isinstance(abon_tariff, AbonTariff) # assert isinstance(abon_tariff, AbonTariff)
self.abon_tariff = abon_tariff self.abon_tariff = abon_tariff
@ -44,25 +45,20 @@ class TariffDefault(TariffBase):
hour=23, minute=59, second=59) hour=23, minute=59, second=59)
return last_month_date return last_month_date
@staticmethod
def description() -> AnyStr:
return _('Base calculate functionality')
class TariffDp(TariffDefault): class TariffDp(TariffDefault):
description = 'IS'
# в IS снимается вся стоимость тарифа вне зависимости от времени использования # в IS снимается вся стоимость тарифа вне зависимости от времени использования
# просто возвращаем всю стоимость тарифа # просто возвращаем всю стоимость тарифа
def calc_amount(self) -> float: def calc_amount(self) -> float:
return float(self.abon_tariff.tariff.amount) return float(self.abon_tariff.tariff.amount)
@staticmethod
def description() -> AnyStr:
return 'IS'
# Как в IS только не на время, а на 10 лет # Как в IS только не на время, а на 10 лет
class TariffCp(TariffDp): class TariffCp(TariffDp):
description = _('Private service')
def calc_deadline(self) -> datetime: def calc_deadline(self) -> datetime:
# делаем время окончания услуги на 10 лет вперёд # делаем время окончания услуги на 10 лет вперёд
nw = timezone.now() nw = timezone.now()
@ -70,10 +66,6 @@ class TariffCp(TariffDp):
hour=23, minute=59, second=59) hour=23, minute=59, second=59)
return long_long_time return long_long_time
@staticmethod
def description() -> AnyStr:
return _('Private service')
# Первый - всегда по умолчанию # Первый - всегда по умолчанию
TARIFF_CHOICES = ( TARIFF_CHOICES = (
@ -84,6 +76,8 @@ TARIFF_CHOICES = (
class PeriodicPayCalcDefault(PeriodicPayCalcBase): class PeriodicPayCalcDefault(PeriodicPayCalcBase):
description = _('Default periodic pay')
def calc_amount(self, model_object) -> float: def calc_amount(self, model_object) -> float:
return model_object.amount return model_object.amount
@ -91,12 +85,10 @@ class PeriodicPayCalcDefault(PeriodicPayCalcBase):
# TODO: решить какой будет расёт периодических платежей # TODO: решить какой будет расёт периодических платежей
return datetime.now() + timedelta(days=30) return datetime.now() + timedelta(days=30)
@staticmethod
def description() -> AnyStr:
return _('Default periodic pay')
class PeriodicPayCalcCustom(PeriodicPayCalcDefault): class PeriodicPayCalcCustom(PeriodicPayCalcDefault):
description = _('Custom periodic pay')
def calc_amount(self, model_object) -> float: def calc_amount(self, model_object) -> float:
""" """
:param model_object: it is a instance of models.PeriodicPay model :param model_object: it is a instance of models.PeriodicPay model
@ -104,10 +96,6 @@ class PeriodicPayCalcCustom(PeriodicPayCalcDefault):
""" """
return uniform(1, 10) return uniform(1, 10)
@staticmethod
def description() -> AnyStr:
return _('Custom periodic pay')
PERIODIC_PAY_CHOICES = ( PERIODIC_PAY_CHOICES = (
('df', PeriodicPayCalcDefault), ('df', PeriodicPayCalcDefault),

Loading…
Cancel
Save