diff --git a/abonapp/models.py b/abonapp/models.py index be12bb2..462f45e 100644 --- a/abonapp/models.py +++ b/abonapp/models.py @@ -5,10 +5,10 @@ from django.core import validators from django.core.exceptions import ValidationError from django.core.validators import RegexValidator from django.db import models, connection, transaction -from django.db.models.signals import post_save, post_delete, pre_delete, post_init +from django.db.models.signals import post_delete, pre_delete, post_init from django.dispatch import receiver from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext_lazy as _, gettext from accounts_app.models import UserProfile, MyUserManager, BaseAccount from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNetworkError @@ -187,13 +187,6 @@ class Abon(BaseAccount): verbose_name_plural = _('Abons') ordering = ['fio'] - # pay something - def make_pay(self, curuser, how_match_to_pay=0.0): - post_save.disconnect(abon_post_save, sender=Abon) - self.ballance -= how_match_to_pay - self.save(update_fields=['ballance']) - post_save.connect(abon_post_save, sender=Abon) - def add_ballance(self, current_user, amount, comment): AbonLog.objects.create( abon=self, @@ -281,6 +274,23 @@ class Abon(BaseAccount): raise LogicError(_('Ip address already exist')) super(Abon, self).save(*args, **kwargs) + def sync_with_nas(self, created: bool): + timeout = None + if hasattr(self, 'is_dhcp') and self.is_dhcp: + timeout = getattr(settings, 'DHCP_TIMEOUT', 14400) + agent_abon = self.build_agent_struct() + if agent_abon is None: + return True + try: + tm = Transmitter() + if created: + tm.add_user(agent_abon, ip_timeout=timeout) + else: + tm.update_user(agent_abon, ip_timeout=timeout) + except (NasFailedResult, NasNetworkError, ConnectionResetError) as e: + print('ERROR:', e) + return True + class PassportInfo(models.Model): series = models.CharField(max_length=4, validators=[validators.integer_validator]) @@ -426,14 +436,10 @@ class PeriodicPayForId(models.Model): next_pay_date = pp.get_next_time_to_pay(self.last_pay) abon = self.account with transaction.atomic(): - abon.make_pay(author, amount) - AbonLog.objects.create( - abon=abon, amount=-amount, - author=author, - comment=comment or _('Charge for "%(service)s"') % { - 'service': self.periodic_pay - } - ) + abon.add_ballance(author, -amount, comment=gettext('Charge for "%(service)s"') % { + 'service': self.periodic_pay + }) + abon.save(update_fields=['ballance']) self.last_pay = now self.next_pay = next_pay_date self.save(update_fields=['last_pay', 'next_pay']) @@ -445,27 +451,6 @@ class PeriodicPayForId(models.Model): db_table = 'periodic_pay_for_id' -@receiver(post_save, sender=Abon) -def abon_post_save(sender, **kwargs): - instance, created = kwargs["instance"], kwargs["created"] - timeout = None - if hasattr(instance, 'is_dhcp') and instance.is_dhcp: - timeout = getattr(settings, 'DHCP_TIMEOUT', 14400) - agent_abon = instance.build_agent_struct() - if agent_abon is None: - return True - try: - tm = Transmitter() - if created: - tm.add_user(agent_abon, ip_timeout=timeout) - else: - tm.update_user(agent_abon, ip_timeout=timeout) - - except (NasFailedResult, NasNetworkError, ConnectionResetError) as e: - print('ERROR:', e) - return True - - @receiver(post_delete, sender=Abon) def abon_del_signal(sender, **kwargs): abon = kwargs["instance"] diff --git a/abonapp/views.py b/abonapp/views.py index 0833be0..4f5a258 100644 --- a/abonapp/views.py +++ b/abonapp/views.py @@ -3,7 +3,7 @@ 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, transaction -from django.db.models import Count, Q, signals +from django.db.models import Count, Q from django.shortcuts import render, redirect, get_object_or_404, resolve_url from django.contrib.auth.decorators import login_required from django.http import HttpResponse, HttpResponseBadRequest @@ -29,7 +29,6 @@ from guardian.shortcuts import get_objects_for_user, assign_perm from guardian.decorators import permission_required_or_403 as permission_required from djing.global_base_views import OrderingMixin - PAGINATION_ITEMS_PER_PAGE = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) @@ -110,6 +109,7 @@ def addabon(request, gid): assign_perm("abonapp.can_buy_tariff", request.user, abon) assign_perm("abonapp.can_view_passport", request.user, abon) assign_perm('abonapp.can_add_ballance', request.user, abon) + abon.sync_with_nas(created=True) messages.success(request, _('create abon success msg')) return redirect('abonapp:abon_home', group.id, abon.pk) else: @@ -145,6 +145,7 @@ def del_abon(request): raise PermissionDenied gid = abon.group.id abon.delete() + abon.sync_with_nas(created=False) messages.success(request, _('delete abon success msg')) return mydefs.res_success(request, resolve_url('abonapp:people_list', gid=gid)) @@ -264,7 +265,8 @@ def abonhome(request, gid, uid): newip = request.POST.get('ip') if newip: abon.ip_address = newip - frm.save() + abon = frm.save() + abon.sync_with_nas(created=False) messages.success(request, _('edit abon success msg')) else: messages.warning(request, _('fix form errors')) @@ -370,6 +372,7 @@ def pick_tariff(request, gid, uid): deadline = datetime.strptime(deadline, '%Y-%m-%d') deadline += timedelta(hours=23, minutes=59, seconds=59) abon.pick_tariff(trf, request.user, deadline=deadline, comment=log_comment) + abon.sync_with_nas(created=False) messages.success(request, _('Tariff has been picked')) return redirect('abonapp:abon_services', gid=gid, uid=abon.id) except (mydefs.LogicError, NasFailedResult) as e: @@ -397,8 +400,10 @@ def pick_tariff(request, gid, uid): @permission_required('abonapp.delete_abontariff') def unsubscribe_service(request, gid, uid, abon_tariff_id): try: + abon = get_object_or_404(models.Abon, pk=uid) abon_tariff = get_object_or_404(models.AbonTariff, pk=int(abon_tariff_id)) abon_tariff.delete() + abon.sync_with_nas(created=False) messages.success(request, _('User has been detached from service')) except NasFailedResult as e: messages.error(request, e) @@ -679,14 +684,17 @@ def abon_ping(request): else: if type(ping_result) is tuple: loses_percent = (ping_result[0] / ping_result[1] if ping_result[1] != 0 else 1) - ping_result = {'all':ping_result[0], 'return': ping_result[1]} + ping_result = {'all': ping_result[0], 'return': ping_result[1]} if loses_percent > 1.0: - text = ' %s' % _('IP Conflict! %(all)d/%(return)d results') % ping_result + text = ' %s' % _( + 'IP Conflict! %(all)d/%(return)d results') % ping_result elif loses_percent > 0.5: - text = ' %s' % _('ok ping, %(all)d/%(return)d loses') % ping_result + text = ' %s' % _( + 'ok ping, %(all)d/%(return)d loses') % ping_result status = True else: - text = ' %s' % _('no ping, %(all)d/%(return)d loses') % ping_result + text = ' %s' % _( + 'no ping, %(all)d/%(return)d loses') % ping_result else: text = ' %s' % _('ping ok') + ' ' + str(ping_result) status = True @@ -760,10 +768,11 @@ def save_user_dev_port(request, gid, uid): other_abon = models.Abon.objects.get(device=abon.device, dev_port=port) if other_abon != abon: user_url = resolve_url('abonapp:abon_home', other_abon.group.id, other_abon.id) - messages.error(request, _("%(user_name)s already pinned to this port on this device") % { - 'user_url': user_url, - 'user_name': other_abon.get_full_name() - }) + messages.error(request, _( + "%(user_name)s already pinned to this port on this device") % { + 'user_url': user_url, + 'user_name': other_abon.get_full_name() + }) return redirect('abonapp:abon_home', gid, uid) except models.Abon.DoesNotExist: pass @@ -899,7 +908,8 @@ def tel_del(request, gid, uid): def phonebook(request, gid): res_format = request.GET.get('f') t1 = models.Abon.objects.filter(group__id=int(gid)).only('telephone', 'fio').values_list('telephone', 'fio') - t2 = models.AdditionalTelephone.objects.filter(abon__group__id=gid).only('telephone', 'owner_name').values_list('telephone', 'owner_name') + t2 = models.AdditionalTelephone.objects.filter(abon__group__id=gid).only('telephone', 'owner_name').values_list( + 'telephone', 'owner_name') tels = list(t1) + list(t2) if res_format == 'csv': import csv @@ -955,10 +965,8 @@ def abon_export(request, gid): @permission_required('group_app.can_view_group', (Group, 'pk', 'gid')) def reset_ip(request, gid, uid): abon = get_object_or_404(models.Abon, pk=uid) - signals.post_save.disconnect(models.abon_post_save, sender=models.Abon) abon.ip_address = None abon.save(update_fields=['ip_address']) - signals.post_save.connect(models.abon_post_save, sender=models.Abon) return HttpResponse(dumps({ 'status': 0, 'dat': "" @@ -1059,17 +1067,17 @@ class EditSibscriberMarkers(UpdateView): def abons(request): ablist = [{ - 'id': abn.pk, - '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()] + 'id': abn.pk, + '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()] tarlist = [{ - 'id': trf.pk, - 'speedIn': trf.speedIn, - 'speedOut': trf.speedOut - } for trf in Tariff.objects.all()] + 'id': trf.pk, + 'speedIn': trf.speedIn, + 'speedOut': trf.speedOut + } for trf in Tariff.objects.all()] data = { 'subscribers': ablist, diff --git a/agent/commands/dhcp.py b/agent/commands/dhcp.py index 2f9ae3f..4ac1972 100644 --- a/agent/commands/dhcp.py +++ b/agent/commands/dhcp.py @@ -21,9 +21,8 @@ def dhcp_commit(client_ip, client_mac, switch_mac, switch_port): print('D:', 'User %s is not access to service' % abon.username) 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)) + abon.sync_with_nas(created=False) except Abon.DoesNotExist: print('N:', "User with device '%s' does not exist" % dev) except Device.DoesNotExist: @@ -41,8 +40,8 @@ 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']) + abon.sync_with_nas(created=False) except Abon.DoesNotExist: pass diff --git a/clientsideapp/locale/ru/LC_MESSAGES/django.po b/clientsideapp/locale/ru/LC_MESSAGES/django.po index 9fcf3b2..79077a7 100644 --- a/clientsideapp/locale/ru/LC_MESSAGES/django.po +++ b/clientsideapp/locale/ru/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-02-28 12:46+0300\n" +"POT-Creation-Date: 2018-03-08 14:24+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Dmitry Novikov nerosketch@gmail.com\n" "Language: ru\n" @@ -19,19 +19,19 @@ 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" -#: clientsideapp/templates/clientsideapp/debt_buy.html:6 +#: templates/clientsideapp/debt_buy.html:6 msgid "Debts" msgstr "Задолженность" -#: clientsideapp/templates/clientsideapp/debt_buy.html:11 +#: templates/clientsideapp/debt_buy.html:11 msgid "repayment of debts" msgstr "Оплатить задолженность" -#: clientsideapp/templates/clientsideapp/debt_buy.html:18 +#: templates/clientsideapp/debt_buy.html:18 msgid "Are you sure you want to spend a payment?" msgstr "Вы уверены что хотите провести платёж?" -#: clientsideapp/templates/clientsideapp/debt_buy.html:21 +#: templates/clientsideapp/debt_buy.html:21 #, fuzzy, python-format #| msgid "" #| "From your account, they withdraw funds in %(amount)s rub.
\n" @@ -48,92 +48,86 @@ msgstr "" "В результате у вас на счету останется %(ballance_after)s руб.
\n" "Администратор сразу сможет видеть что у вас закрыта задолженность." -#: clientsideapp/templates/clientsideapp/debt_buy.html:24 +#: templates/clientsideapp/debt_buy.html:24 msgid "Description of payment" msgstr "Описание платежа" -#: clientsideapp/templates/clientsideapp/debt_buy.html:32 +#: templates/clientsideapp/debt_buy.html:32 msgid "Confirm" msgstr "Подтвердить" -#: clientsideapp/templates/clientsideapp/debt_buy.html:35 +#: templates/clientsideapp/debt_buy.html:35 msgid "Cancel" msgstr "Отменить" -#: clientsideapp/templates/clientsideapp/modal_service_buy.html:5 +#: templates/clientsideapp/modal_service_buy.html:5 msgid "Pick service" msgstr "Заказать услугу" -#: clientsideapp/templates/clientsideapp/modal_service_buy.html:8 +#: templates/clientsideapp/modal_service_buy.html:8 msgid "Are you sure you want to order the service?" msgstr "Вы уверены что хотите заказать услугу?" +#: templates/clientsideapp/modal_service_buy.html:15 +#, python-format +msgid "" +"Inbound speed: %(speedIn)s MBit/s
\n" +"Outgoing speed: %(speedOut)s MBit/s
\n" +"Cost: %(amount)s rubles." +msgstr "" -#: clientsideapp/templates/clientsideapp/modal_service_buy.html:28 +#: templates/clientsideapp/modal_service_buy.html:22 +#: templates/clientsideapp/services.html:59 msgid "Pick" msgstr "Заказать" -#: clientsideapp/templates/clientsideapp/modal_service_buy.html:30 +#: templates/clientsideapp/modal_service_buy.html:24 msgid "Close" msgstr "Закрыть" -#: clientsideapp/templates/clientsideapp/pays.html:6 +#: templates/clientsideapp/pays.html:6 msgid "conducted payments" msgstr "Проведённые платежи" -#: clientsideapp/templates/clientsideapp/pays.html:11 +#: templates/clientsideapp/pays.html:11 msgid "Transaction Amount (rubles)" msgstr "Сумма транзакции (руб)" -#: clientsideapp/templates/clientsideapp/pays.html:12 +#: templates/clientsideapp/pays.html:12 msgid "Date of transaction" msgstr "Дата транзакции" -#: clientsideapp/templates/clientsideapp/pays.html:13 +#: templates/clientsideapp/pays.html:13 msgid "Comment" msgstr "Комментарий" -#: clientsideapp/templates/clientsideapp/pays.html:25 +#: templates/clientsideapp/pays.html:25 msgid "You have not spent payments" msgstr "У вас нет проведённых платежей" -#: clientsideapp/views.py:53 +#: templates/clientsideapp/services.html:25 +msgid "currency" +msgstr "" + +#: views.py:51 #, 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 +#: views.py:54 #, python-format msgid "The service '%s' wan successfully activated" msgstr "Услуга '%s' успешно подключена" -#: clientsideapp/views.py:181 +#: views.py:84 msgid "Are you not sure that you want buy the service?" msgstr "Вы не уверены что хотите оплатить долг?" -#: clientsideapp/views.py:183 +#: views.py:86 msgid "Your account have not enough money" msgstr "Недостаточно средств на счету" + +#: views.py:90 +#, python-format +msgid "%(username)s paid the debt %(amount).2f" +msgstr "%(username)s заплатил долг в размере %(amount).2f" diff --git a/clientsideapp/views.py b/clientsideapp/views.py index dccd7cd..fe7db8b 100644 --- a/clientsideapp/views.py +++ b/clientsideapp/views.py @@ -4,7 +4,7 @@ from django.contrib.gis.shortcuts import render_to_text from django.shortcuts import render, get_object_or_404, redirect from django.contrib import messages from django.db import transaction -from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext_lazy as _, gettext from abonapp.models import AbonLog, InvoiceForPayment, Abon from tariff_app.models import Tariff @@ -50,6 +50,7 @@ def buy_service(request, srv_id): if request.method == 'POST': abon.pick_tariff(service, request.user, _("Buy the service via user side, service '%s'") % service) + abon.abon.sync_with_nas(created=False) messages.success(request, _("The service '%s' wan successfully activated") % service.title) else: return render_to_text('clientsideapp/modal_service_buy.html', { @@ -84,9 +85,13 @@ def debt_buy(request, d_id): if abon.ballance < debt.amount: raise LogicError(_('Your account have not enough money')) - abon.make_pay(request.user, debt.amount) - debt.set_ok() + amount = -debt.amount + abon.add_ballance(request.user, amount, comment=gettext('%(username)s paid the debt %(amount).2f') % { + 'username': abon.get_full_name(), + 'amount': amount + }) abon.save(update_fields=['ballance']) + debt.set_ok() debt.save(update_fields=['status', 'date_pay']) return redirect('client_side:debts') except LogicError as e: diff --git a/migrate_to_0.2.py b/migrate_to_0.2.py deleted file mode 100755 index 86fb8dd..0000000 --- a/migrate_to_0.2.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import os -from json import dump -import django - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings") -django.setup() -from django.db.models import fields as django_fields - - -def get_fixture_from_unchanget_model(model_name: str, model_class): - """ - Создаёт фикстуру если модели между версиями не изменились - :param model_name: str 'app_label.model_name' - :param model_class: Model модель для которой надо сделать фикстуру - :return: список словарей - """ - print(model_name) - - def get_fields(obj): - fields = dict() - for field in obj._meta.get_fields(): - if isinstance(field, django_fields.reverse_related.ManyToOneRel) or \ - isinstance(field, django_fields.reverse_related.ManyToManyRel): - continue - field_val = getattr(obj, field.name) - if field_val is None: - continue - if isinstance(field, django_fields.related.ManyToManyField): - fields[field.name] = [f.pk for f in field_val.all()] - elif isinstance(field, django_fields.related.ForeignKey): - fields[field.name] = field_val.pk - elif isinstance(field, django_fields.FloatField): - fields[field.name] = float(field_val) - elif isinstance(field, django_fields.DateTimeField): - fields[field.name] = str(field_val) - elif isinstance(field, django_fields.AutoField): - continue - else: - fields[field.name] = field_val - return fields - res = [{ - 'model': model_name, - 'pk': obj.pk, - 'fields': get_fields(obj) - } for obj in model_class.objects.all()] - return res - - -def dump_abonapp(): - from abonapp import models - res = [{ - 'model': 'group_app.group', - 'pk': abon_group.pk, - 'fields': { - 'title': abon_group.title - } - } for abon_group in models.AbonGroup.objects.all()] - - #res += get_fixture_from_unchanget_model('abonapp.abonlog', models.AbonLog) - - res += get_fixture_from_unchanget_model('abonapp.abontariff', models.AbonTariff) - - res += get_fixture_from_unchanget_model('abonapp.abonstreet', models.AbonStreet) - - res += get_fixture_from_unchanget_model('abonapp.extrafieldsmodel', models.ExtraFieldsModel) - - res += get_fixture_from_unchanget_model('abonapp.abon', models.Abon) - '''res += [{ - 'model': 'abonapp.abon', - 'pk': ab.pk, - 'fields': { - 'current_tariff': ab.current_tariff.pk, - 'group': ab.group.pk, - 'ballance': ab.ballance, - 'ip_address': ab.ip_address, - 'description': ab.description, - 'street': ab.street, - 'house': ab.house, - 'extra_fields': [pid.pk for pid in ab.extra_fields.all()], - 'device': ab.device.pk, - 'dev_port': ab.dev_port.pk, - 'is_dynamic_ip': ab.is_dynamic_ip - } - } for ab in models.Abon.objects.all()]''' - - res += get_fixture_from_unchanget_model('abonapp.passportinfo', models.PassportInfo) - - res += get_fixture_from_unchanget_model('abonapp.invoiceforpayment', models.InvoiceForPayment) - - res += get_fixture_from_unchanget_model('abonapp.alltimepaylog', models.AllTimePayLog) - - res += get_fixture_from_unchanget_model('abonapp.abonrawpassword', models.AbonRawPassword) - - res += get_fixture_from_unchanget_model('abonapp.additionaltelephone', models.AdditionalTelephone) - - res += get_fixture_from_unchanget_model('abonapp.periodicpayforid', models.PeriodicPayForId) - - return res - - -def dump_tariffs(): - from tariff_app import models - res = get_fixture_from_unchanget_model('tariff_app.Tariff', models.Tariff) - - res += get_fixture_from_unchanget_model('tariff_app.periodicpay', models.PeriodicPay) - - return res - - -def dump_devs(): - pass - #from devapp import models - - - -def make_migration(): - from datetime import datetime - from datetime import date - - def my_date_converter(o): - if isinstance(o, datetime) or isinstance(o, date): - return "%s" % o - - def appdump(fname, func): - with open(fname, 'w') as f: - dump(func(), f, default=my_date_converter, ensure_ascii=False) - - appdump('abon_fixture.json', dump_abonapp) - appdump('tariffs_fixture.json', dump_tariffs) - - - -if __name__ == '__main__': - make_migration()