Browse Source

Merge branch 'devel' of https://github.com/bashmak/djing into tariffs

devel
Dmitry 9 years ago
parent
commit
b9b5889ca2
  1. 33
      abonapp/tests.py
  2. 8
      agent/mod_mikrotik.py
  3. 16
      agent/settings.py
  4. 85
      clientsideapp/views.py
  5. 69
      djing/utils/load_from_nodeny.py
  6. 190
      djing/utils/save_from_nodeny.py
  7. 15
      taskapp/handle.py
  8. 362
      taskapp/locale/ru/LC_MESSAGES/django.po
  9. 15
      taskapp/models.py
  10. 19
      taskapp/views.py

33
abonapp/tests.py

@ -1,3 +1,4 @@
from django.shortcuts import resolve_url
from django.test import TestCase
from django.test.client import Client
from agent import NasNetworkError
@ -86,11 +87,12 @@ class AbonTestCase(TestCase):
c = Client()
# login
c.post('/accounts/login/', {'login': '1234567', 'password': 'ps'})
resp = c.get('/abons/1/1/complete_service1')
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('/abons/1/1/complete_service1', data={
resp = c.post(url, data={
'finish_confirm': 'yes'
})
print('RESP:', resp)
@ -108,13 +110,16 @@ class AbonTestCase(TestCase):
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()
r = c.get('/abons/pay', {
url = resolve_url('abonapp:terminal_pay')
r = c.get(url, {
'ACT': 1, 'PAY_ACCOUNT': '1234567',
'SERVICE_ID': pay_SERV_ID,
'PAY_ID': 3561234,
@ -123,7 +128,7 @@ class AbonTestCase(TestCase):
})
xobj = xmltodict.parse(r.content)
self.assertEqual(int(xobj['pay-response']['status_code']), 21)
r = c.get('/abons/pay', {
r = c.get(url, {
'ACT': 4, 'PAY_ACCOUNT': '1234567',
'SERVICE_ID': pay_SERV_ID,
'PAY_ID': 3561234,
@ -133,7 +138,7 @@ class AbonTestCase(TestCase):
})
xobj = xmltodict.parse(r.content)
self.assertEqual(int(xobj['pay-response']['status_code']), 22)
r = c.get('/abons/pay', {
r = c.get(url, {
'ACT': 4, 'PAY_ACCOUNT': '1234567',
'SERVICE_ID': pay_SERV_ID,
'PAY_ID': 3561234,
@ -143,7 +148,7 @@ class AbonTestCase(TestCase):
})
xobj = xmltodict.parse(r.content)
self.assertEqual(int(xobj['pay-response']['status_code']), -100)
r = c.get('/abons/pay', {
r = c.get(url, {
'ACT': 7, 'PAY_ACCOUNT': '1234567',
'SERVICE_ID': pay_SERV_ID,
'PAY_ID': 3561234,
@ -166,10 +171,11 @@ class AbonTestCase(TestCase):
def test_add_abon(self):
c = Client()
c.login(username='1234567', password='ps')
r = c.get('/abons/1/addabon')
url = resolve_url('abonapp:add_abon', gid=1)
r = c.get(url)
# поглядим на страницу добавления абонента
self.assertEqual(r.status_code, 200)
r = c.post('/abons/1/addabon', {
r = c.post(url, {
'username': '123',
'password': 'ps',
'fio': 'Abon Fio',
@ -177,7 +183,7 @@ class AbonTestCase(TestCase):
'is_active': True
})
self.assertEqual(r.status_code, 302)
r = c.get('/abons/324/addabon')
r = c.get(resolve_url('abonapp:add_abon', gid=324))
self.assertEqual(r.status_code, 404)
try:
abn = Abon.objects.get(username='123')
@ -191,6 +197,13 @@ class AbonTestCase(TestCase):
# должен быть пароль абонента простым текстом
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):

8
agent/mod_mikrotik.py

@ -226,7 +226,9 @@ class QueueManager(TransmitterManager):
'=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)
'=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
'=queue=MikroBILL_SFQ/MikroBILL_SFQ',
'=burst-time=1/1'
])
def remove(self, user):
@ -251,7 +253,9 @@ class QueueManager(TransmitterManager):
'=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()
'=target=%s' % user.ip.get_str(),
'=queue=MikroBILL_SFQ/MikroBILL_SFQ',
'=burst-time=1/1'
])
# читаем шейпер, возващаем записи о шейпере

16
agent/settings.py

@ -1,16 +0,0 @@
# -*- coding: utf-8 -*-
# Для установки модуля NAS смотрите в __init__
# Certificates
CERTFILE = "/etc/ssl/server.crt"
KEYFILE = "/etc/ssl/server.key"
# Использовать-ли при передаче инфы между NAS и основным сервером SSL
IS_USE_SSL = False
NAS_IP = '10.12.1.11'
NAS_LOGIN = 'admin'
NAS_PASSW = '2ekc3'
NAS_PORT = 8728

85
clientsideapp/views.py

@ -43,18 +43,23 @@ def services(request):
def buy_service(request, srv_id):
abon = get_object_or_404(Abon, id=request.user.pk)
service = get_object_or_404(Tariff, id=srv_id)
current_service = abon.active_tariff()
if request.method == 'POST':
abon.pick_tariff(service, request.user, 'Покупка тарифного плана через личный кабинет, тариф "%s"'
% service)
messages.success(request, 'Вы подписались на новую услугу. Она встала на очередь подключений. '
'Когда закончится ваша текущая услуга, то включится эта')
return redirect('client_side:services')
return render_to_text('clientsideapp/modal_service_buy.html', {
'service': service,
'current_service': current_service
}, request=request)
try:
current_service = abon.active_tariff()
if request.method == 'POST':
abon.pick_tariff(service, request.user, 'Покупка тарифного плана через личный кабинет, тариф "%s"'
% service)
messages.success(request, 'Вы подписались на новую услугу. Она встала на очередь подключений. '
'Когда закончится ваша текущая услуга, то включится эта')
else:
return render_to_text('clientsideapp/modal_service_buy.html', {
'service': service,
'current_service': current_service
}, request=request)
except LogicError as e:
messages.error(request, e)
except NasFailedResult as e:
messages.error(request, e)
return redirect('client_side:services')
@login_required
@ -62,30 +67,36 @@ def complete_service(request, srv_id):
abtar = get_object_or_404(AbonTariff, id=srv_id)
service = abtar.tariff
if request.method == 'POST':
# досрочно завершаем услугу
finish_confirm = request.POST.get('finish_confirm')
if finish_confirm == 'yes':
# удаляем запись о текущей услуге.
abtar.delete()
messages.success(request, 'Услуга "%s" успешно завершена' % service.title)
AbonLog.objects.create(
abon=abtar.abon,
amount=0.0,
author=abtar.abon,
comment='Досрочное завершение услуги "%s" из личного кабинета' % service.title
)
try:
if request.method == 'POST':
# досрочно завершаем услугу
finish_confirm = request.POST.get('finish_confirm')
if finish_confirm == 'yes':
# удаляем запись о текущей услуге.
abtar.delete()
messages.success(request, 'Услуга "%s" успешно завершена' % service.title)
AbonLog.objects.create(
abon=abtar.abon,
amount=0.0,
author=abtar.abon,
comment='Досрочное завершение услуги "%s" из личного кабинета' % service.title
)
else:
messages.error(request, 'Действие не подтверждено')
else:
messages.error(request, 'Действие не подтверждено')
return redirect('client_side:services')
time_use = RuTimedelta(timezone.now() - abtar.time_start)
return render_to_text('clientsideapp/modal_complete_service.html', {
'service': service,
'abtar': abtar,
'time_use': time_use
}, request=request)
time_use = RuTimedelta(timezone.now() - abtar.time_start)
return render_to_text('clientsideapp/modal_complete_service.html', {
'service': service,
'abtar': abtar,
'time_use': time_use
}, request=request)
except LogicError as e:
messages.error(request, e)
except NasFailedResult as e:
messages.error(request, e)
except NasNetworkError:
messages.error(request, 'Временные неполадки')
return redirect('client_side:services')
@login_required
@ -107,6 +118,10 @@ def unsubscribe_service(request, srv_id):
}, request=request)
except AbonTariff.DoesNotExist:
messages.error(request, 'Указанная подписка на услугу не найдена')
except NasFailedResult as e:
messages.error(request, e)
except NasNetworkError:
messages.error(request, 'Временные неполадки')
return redirect('client_side:services')

69
djing/utils/load_from_nodeny.py

@ -1,48 +1,55 @@
#!/bin/env python2
#!/bin/env python3
# coding=utf-8
import os
import MySQLdb
from json import dumps
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings")
db = MySQLdb.connect(host="localhost", user="root", passwd="PASSWORD", db="nodeny", charset='utf8')
cursor = db.cursor()
result = dict()
def load_users(cursor, grp_id):
# выбираем абонентов
sql = r"SELECT users.name, users.fio, data0._adr_telefon, dictionary.v, data0._adr_house, data0._birthday, users.grp FROM users LEFT JOIN data0 ON (data0.uid=users.id) LEFT JOIN dictionary ON (dictionary.k=data0._adr_street AND dictionary.type='street') WHERE users.grp=23"
sql = r"SELECT users.name, users.fio, data0._adr_telefon, dictionary.v AS street, data0._adr_house, data0._birthday, users.grp, INET_NTOA(ip_pool.ip) AS ip, users.balance, AES_DECRYPT(users.passwd, 'Vu6saiZa') as decr_passwd FROM users LEFT JOIN data0 ON (data0.uid = users.id) LEFT JOIN dictionary ON (dictionary.k = data0._adr_street AND dictionary.type = 'street') LEFT JOIN ip_pool ON (ip_pool.uid = users.id) WHERE users.grp = %d" % grp_id
cursor.execute(sql)
result['users'] = list()
res = cursor.fetchone()
while res:
result['users'].append({
'name': res[0],
'fio': res[1],
'tel': res[2],
'addr': u"ул. %s д. %s" % (res[3], res[4]),
'birth': int(res[5]),
'grp': int(res[6])
})
res = cursor.fetchone()
users = [{
'name': str(res[0]),
'fio': str(res[1]),
'tel': str(res[2]),
'street': str(res[3] or ''),
'house': str(res[4]),
'birth': res[5],
'grp': int(res[6]),
'ip': str(res[7] or ''),
'balance': float(res[8]),
'passw': res[9].decode("utf-8") if res[9] is not None else ''
} for res in cursor.fetchall()]
return users
def load_groups(cursor):
# выбираем группы
sql = r'SELECT grp_id, grp_name FROM user_grp'
cursor.execute(sql)
result['groups'] = list()
res = cursor.fetchone()
while res:
result['groups'].append({
groups = list()
for res in cursor.fetchall():
users = load_users(cursor=cursor, grp_id=int(res[0]))
groups.append({
'gid': int(res[0]),
'gname': res[1]
'gname': res[1],
'users': users
})
res = cursor.fetchone()
return groups
if __name__ == "__main__":
db = MySQLdb.connect(host="127.0.0.1", user="<username>", passwd="<password>", db="db", charset='utf8')
cursor = db.cursor()
result = dict()
result['groups'] = load_groups(cursor=cursor)
db.close()
f = open('dump_chkal.json', 'w')
f.write(dumps(result, ensure_ascii=False).encode('utf8'))
f = open('dump.json', 'w')
f.write(dumps(result, ensure_ascii=False))
f.close()

190
djing/utils/save_from_nodeny.py

@ -4,67 +4,143 @@
import os
from json import load
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings")
django.setup()
from abonapp.models import Abon, AbonGroup, AbonRawPassword, AbonStreet
from ip_pool.models import IpPoolItem
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings")
django.setup()
from abonapp.models import Abon, AbonGroup, AbonTariff, AbonRawPassword
from ip_pool.models import IpPoolItem
from tariff_app.models import Tariff
from accounts_app.models import UserProfile
with open('dump_pshen.json', 'r') as f:
dat = load(f)
#for dt in dat['groups']:
# try:
# grp = AbonGroup.objects.get(title=dt['gname'])
# except AbonGroup.DoesNotExist:
# grp = AbonGroup(title=dt['gname'])
# grp.save()
# dt['obj'] = grp
grp = AbonGroup.objects.get(id=43)
pshen_trf = Tariff.objects.get(id=3)
print(pshen_trf)
iam = UserProfile.objects.get(id=1)
for dt in dat['users']:
#grp = [gr for gr in dat['groups'] if dt['grp']==gr['gid']]
#grp = grp[0]['obj'] if len(grp)>0 else None
class DumpAbon(object):
def __init__(self, obj=None):
if obj is None: return
self.name = obj['name']
self.fio = obj['fio']
self.tel = obj['tel']
self.street = obj['street']
self.house = obj['house']
self.birth = obj['birth']
self.grp = obj['grp']
self.ip = obj['ip']
self.balance = obj['balance']
self.passw = obj['passw']
@staticmethod
def build_from_django(obj):
assert isinstance(obj, Abon)
self = DumpAbon()
self.name = obj.username
self.fio = obj.fio
self.tel = obj.telephone
self.street = obj.street
self.house = obj.house
self.birth = obj.birth_day
self.grp = obj.group.pk
self.ip = obj.ip_address
self.balance = obj.ballance
try:
abon = Abon.objects.get(username=dt['name'])
except Abon.DoesNotExist:
abon = Abon(username=dt['name'])
raw_passw = AbonRawPassword.objects.get(account=obj)
except AbonRawPassword.DoesNotExist:
raw_passw = ''
self.passw = raw_passw
return self
def __eq__(self, other):
assert isinstance(other, DumpAbon)
r = self.name == other.name
r = r and self.name == other.name
r = r and self.fio == other.fio
r = r and self.tel == other.tel
r = r and self.street == other.street
r = r and self.house == other.house
r = r and self.birth == other.birth
r = r and self.grp == other.grp
r = r and self.ip == other.ip
r = r and self.balance == other.ballance
return r
def __ne__(self, other):
return not self.__eq__(other)
def load_users(obj, group):
for usr in obj:
# абонент из дампа
dump_abon = DumpAbon(usr)
# абонент из биллинга
print('\t', dump_abon.name, dump_abon.fio, dump_abon.ip)
try:
ip_addr = IpPoolItem.objects.get(ip=dt['ip'])
except IpPoolItem.DoesNotExist:
ip_addr = None
abon.fio = dt['fio']
abon.telephone=dt['tel']
abon.house=dt['addr']
abon.group=grp
abon.ballance=dt['balance']
abon.ip_address=ip_addr
abon.set_password(dt['passw'])
abon.save()
abon = Abon.objects.get(username=dump_abon.name)
bl_abon = DumpAbon.build_from_django(abon)
if bl_abon != dump_abon:
update_user(abon, dump_abon, group)
except Abon.DoesNotExist:
# добавляем абонента
add_user(dump_abon, group)
def add_user(obj, user_group):
assert isinstance(obj, DumpAbon)
street = None
ip = None
try:
ip = IpPoolItem.objects.get(ip=obj.ip)
street = AbonStreet.objects.get(name=obj.street)
except IpPoolItem.DoesNotExist:
ip = IpPoolItem.objects.create(ip=obj.ip)
except AbonStreet.DoesNotExist:
street = AbonStreet.objects.create(name=obj.street, group=user_group)
Abon.objects.create(
username=obj.name,
fio=obj.fio,
telephone=obj.tel,
street=street,
house=obj.house,
birth_day=obj.birth,
group = user_group,
ip_address=ip,
ballance=obj.balance
)
def update_user(db_abon, obj, user_group):
assert isinstance(obj, DumpAbon)
assert isinstance(db_abon, Abon)
street = None
ip = None
try:
ip = IpPoolItem.objects.get(ip=obj.ip)
street = AbonStreet.objects.get(name=obj.street, group=user_group)
except IpPoolItem.DoesNotExist:
if obj.ip:
ip = IpPoolItem.objects.create(ip=obj.ip)
except AbonStreet.DoesNotExist:
street = AbonStreet.objects.create(name=obj.street, group=user_group)
db_abon.fio = obj.fio
db_abon.telephone = obj.tel
db_abon.street = street
db_abon.house = obj.house
#db_abon.birth_day = datetime(obj.birth)
db_abon.group = user_group
db_abon.ip_address = ip
db_abon.ballance = obj.balance
db_abon.save()
if __name__ == "__main__":
with open('dump.json', 'r') as f:
dat = load(f)
for grp in dat['groups']:
try:
abon_raw_passw = AbonRawPassword.objects.get(account=abon)
abon_raw_passw.passw_text = dt['passw']
abon_raw_passw.save(update_fields=['passw_text'])
except AbonRawPassword.DoesNotExist:
AbonRawPassword.objects.create(
account=abon,
passw_text=dt['passw']
abgrp=AbonGroup.objects.get(title=grp['gname'])
except AbonGroup.DoesNotExist:
abgrp = AbonGroup.objects.create(
title=grp['gname']
)
abtrfs = AbonTariff.objects.filter(abon=abon)
if abtrfs.count() > 0:
abtrf = abtrfs[0]
else:
abtrf = AbonTariff()
abtrf.abon = abon
abtrf.tariff = pshen_trf
abtrf.save()
abtrf.activate(iam)
print(abon.username, abon.fio, abon.group, ip_addr)
print(grp['gname'])
load_users(grp['users'], abgrp)

15
taskapp/handle.py

@ -21,16 +21,19 @@ def handle(task, author, recipient, abon_group):
# Если задача завершена
elif task.state == 'F':
text = _('Task completed')
# Меняем телефон назначения на телефон автора, т.к. при завершении
# Меняем цель назначения на автора, т.к. при завершении
# идёт оповещение автору о выполнении
dst_account = author
fulltext="%s: %s. " % (text, task.abon.get_full_name())
fulltext="%s:\n%s\n" % (text, task.abon.get_full_name())
fulltext += _('locality %s.\n') % abon_group.title
if task.abon:
fulltext += _('address %(task.abon.address)s. telephone %(task.abon.telephone)s. ') % (
task.abon.address, task.abon.telephone
fulltext += _('address %s %s.\ntelephone %s\n') % (
task.abon.street.name if task.abon.street is not None else '<'+_('not chosen')+'>',
task.abon.house,
task.abon.telephone
)
fulltext += _('locality %(abon_group.title)s. Task type - %(task.get_mode_display)s. ') % (abon_group.title, task.get_mode_display())
fulltext += task.descr if task.descr else _('Not assigned')
fulltext += _('Task type - %s.\n') % task.get_mode_display()
fulltext += task.descr if task.descr else ''
send_notify(fulltext, dst_account)
except ChatException as e:
raise TaskException(e)

362
taskapp/locale/ru/LC_MESSAGES/django.po

@ -1,362 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Dmitry Novikov nerosketch@gmail.com, 2017.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-27 12:27+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%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"
#: taskapp/forms.py:16
msgid "Short description"
msgstr "Краткое описание"
#: taskapp/handle.py:14
msgid "Task"
msgstr "Задача"
#: taskapp/handle.py:23
msgid "Task completed"
msgstr "Задача завершена"
#: taskapp/handle.py:29
#, python-format
msgid "address %s. telephone %s. "
msgstr "по адресу %s тел. %s. "
#: taskapp/handle.py:32
#, python-format
msgid "locality %s. Task type - %s. "
msgstr "с. %s. Тип задачи - %s. "
#: taskapp/handle.py:33 taskapp/templates/taskapp/view.html.py:34
msgid "Not assigned"
msgstr "&lt;Не назначено&gt;"
#: taskapp/models.py:13
msgid "Higher"
msgstr "Высший"
#: taskapp/models.py:14
msgid "Average"
msgstr "Средний"
#: taskapp/models.py:15
msgid "Low"
msgstr "Низкий"
#: taskapp/models.py:19
msgid "New"
msgstr "Новая"
#: taskapp/models.py:20
msgid "In fulfilling"
msgstr "На выполнении"
#: taskapp/models.py:21
msgid "Completed"
msgstr "Выполнена"
#: taskapp/models.py:25
msgid "not chosen"
msgstr "не выбрано"
#: taskapp/models.py:26
msgid "yellow triangle"
msgstr "жёлтый треугольник"
#: taskapp/models.py:27
msgid "red cross"
msgstr "красный крестик"
#: taskapp/models.py:28
msgid "weak speed"
msgstr "слабая скорость"
#: taskapp/models.py:29
msgid "cable break"
msgstr "обрыв кабеля"
#: taskapp/models.py:30
msgid "connection"
msgstr "подключение"
#: taskapp/models.py:31
msgid "periodic disappearance"
msgstr "переодическое пропадание"
#: taskapp/models.py:32
msgid "router setup"
msgstr "настройка роутера"
#: taskapp/models.py:33
msgid "configure onu"
msgstr "настроить onu"
#: taskapp/models.py:34
msgid "crimp cable"
msgstr "обжать кабель"
#: taskapp/models.py:35
msgid "other"
msgstr "другое"
#: taskapp/models.py:42
msgid "Change task"
msgstr "Изменение задачи"
#: taskapp/models.py:43
msgid "Create task"
msgstr "Создание задачи"
#: taskapp/models.py:44
msgid "Delete task"
msgstr "Удаление задачи"
#: taskapp/models.py:45
msgid "Completing tasks"
msgstr "Завершение задачи"
#: taskapp/models.py:46
msgid "The task started"
msgstr "Задача начата"
#: taskapp/models.py:77
msgid "Access to all tasks"
msgstr "Доступ ко всем задачам"
#: taskapp/models.py:78
msgid "Reminders of tasks"
msgstr "Напоминания о задачах"
#: taskapp/templates/taskapp/add_edit_task.html:7
#: taskapp/templates/taskapp/tasklist_all.html:7
#: taskapp/templates/taskapp/view.html:7
msgid "Tasks"
msgstr "Задачи"
#: taskapp/templates/taskapp/add_edit_task.html:8
#: taskapp/templates/taskapp/tasklist.html:48
#: taskapp/templates/taskapp/tasklist_active.html:46
#: taskapp/templates/taskapp/tasklist_all.html:54
#: taskapp/templates/taskapp/tasklist_finish.html:43
#: taskapp/templates/taskapp/tasklist_own.html:40
msgid "Edit"
msgstr "Редактировать"
#: taskapp/templates/taskapp/add_edit_task.html:8
msgid "Create"
msgstr "Создать"
#: taskapp/templates/taskapp/add_edit_task.html:15
#: taskapp/templates/taskapp/footer_btns.html:3
#: taskapp/templates/taskapp/footer_btns.html:4
#: taskapp/templates/taskapp/tasklist_all.html:75
#: taskapp/templates/taskapp/tasklist_all.html:76
msgid "Add new task"
msgstr "Добавьте новую задачу"
#: taskapp/templates/taskapp/add_edit_task.html:27
#: taskapp/templates/taskapp/tasklist.html:10
#: taskapp/templates/taskapp/tasklist_active.html:10
#: taskapp/templates/taskapp/tasklist_all.html:22
#: taskapp/templates/taskapp/tasklist_finish.html:10
#: taskapp/templates/taskapp/tasklist_own.html:10
#: taskapp/templates/taskapp/view.html:19
msgid "Description"
msgstr "Описание"
#: taskapp/templates/taskapp/add_edit_task.html:35
#: taskapp/templates/taskapp/tasklist.html:12
#: taskapp/templates/taskapp/tasklist_active.html:12
#: taskapp/templates/taskapp/tasklist_all.html:24
#: taskapp/templates/taskapp/tasklist_finish.html:12
#: taskapp/templates/taskapp/tasklist_own.html:11
msgid "The nature of the damage"
msgstr "Характер поломки"
#: taskapp/templates/taskapp/add_edit_task.html:43
#: taskapp/templates/taskapp/tasklist.html:14
#: taskapp/templates/taskapp/tasklist_active.html:14
#: taskapp/templates/taskapp/tasklist_all.html:26
#: taskapp/templates/taskapp/tasklist_finish.html:14
#: taskapp/templates/taskapp/tasklist_own.html:13
msgid "A priority"
msgstr "Приоритет"
#: taskapp/templates/taskapp/add_edit_task.html:51
#: taskapp/templates/taskapp/tasklist.html:13
#: taskapp/templates/taskapp/tasklist_active.html:13
#: taskapp/templates/taskapp/tasklist_all.html:25
#: taskapp/templates/taskapp/tasklist_finish.html:13
#: taskapp/templates/taskapp/tasklist_own.html:12
msgid "Condition"
msgstr "Состояние"
#: taskapp/templates/taskapp/add_edit_task.html:59
#: taskapp/templates/taskapp/view.html:30
msgid "Subscriber"
msgstr "Абонент"
#: taskapp/templates/taskapp/add_edit_task.html:75
msgid "Reality (the date by which you must complete the task)"
msgstr "Актуальность (дата, до которой нужно завершить задачу)"
#: taskapp/templates/taskapp/add_edit_task.html:91
msgid "Attached image"
msgstr "Прикреплённое изображение"
#: taskapp/templates/taskapp/add_edit_task.html:99
msgid "Save"
msgstr "Сохранить"
#: taskapp/templates/taskapp/add_edit_task.html:102
msgid "Reset"
msgstr "Сбросить"
#: taskapp/templates/taskapp/footer_btns.html:9
msgid "View all tasks"
msgstr "Просмотреть все задачи"
#: taskapp/templates/taskapp/tasklist.html:11
#: taskapp/templates/taskapp/tasklist_active.html:11
#: taskapp/templates/taskapp/tasklist_all.html:23
#: taskapp/templates/taskapp/tasklist_finish.html:11
msgid "Task author"
msgstr "Кто назначил"
#: taskapp/templates/taskapp/tasklist.html:15
#: taskapp/templates/taskapp/tasklist_active.html:15
#: taskapp/templates/taskapp/tasklist_all.html:27
#: taskapp/templates/taskapp/tasklist_finish.html:15
#: taskapp/templates/taskapp/tasklist_own.html:14
#: taskapp/templates/taskapp/view.html:27
msgid "Date of create"
msgstr "Дата создания"
#: taskapp/templates/taskapp/tasklist.html:16
#: taskapp/templates/taskapp/tasklist_active.html:16
#: taskapp/templates/taskapp/tasklist_all.html:28
#: taskapp/templates/taskapp/tasklist_finish.html:16
#: taskapp/templates/taskapp/tasklist_own.html:15
#: taskapp/templates/taskapp/view.html:37
msgid "Attachment"
msgstr "Приложение"
#: taskapp/templates/taskapp/tasklist.html:17
#: taskapp/templates/taskapp/tasklist_active.html:17
#: taskapp/templates/taskapp/tasklist_all.html:29
#: taskapp/templates/taskapp/tasklist_finish.html:17
#: taskapp/templates/taskapp/tasklist_own.html:16
msgid "Actions"
msgstr "Действия"
#: taskapp/templates/taskapp/tasklist.html:41
msgid "Begin"
msgstr "Начать"
#: taskapp/templates/taskapp/tasklist.html:44
#: taskapp/templates/taskapp/tasklist_active.html:42
msgid "Complete"
msgstr "Завершить"
#: taskapp/templates/taskapp/tasklist.html:56
#: taskapp/templates/taskapp/tasklist_active.html:54
#: taskapp/templates/taskapp/tasklist_all.html:67
#: taskapp/templates/taskapp/tasklist_finish.html:56
msgid "The list is empty"
msgstr "Список пуст"
#: taskapp/templates/taskapp/tasklist_all.html:8
msgid "All tasks"
msgstr "Все задачи"
#: taskapp/templates/taskapp/tasklist_all.html:14
msgid "Records of all the tasks in the system"
msgstr "Лог всех задач в системе"
#: taskapp/templates/taskapp/tasklist_all.html:59
#: taskapp/templates/taskapp/tasklist_own.html:45
msgid "Remind"
msgstr "Напомнить"
#: taskapp/templates/taskapp/tasklist_finish.html:48
#: taskapp/templates/taskapp/tasklist_own.html:50
msgid "Delete"
msgstr "Удалить"
#: taskapp/templates/taskapp/tasklist_own.html:58
msgid "All your tasks has been performed"
msgstr "Все ваши задачи выполнены"
#: taskapp/templates/taskapp/view.html:15
msgid "Task description"
msgstr "Описание задачи"
#: taskapp/templates/taskapp/view.html:20
msgid "Implementers"
msgstr "Исполнители"
#: taskapp/templates/taskapp/view.html:26
msgid "The task is valid until"
msgstr "Задача действительна до"
#: taskapp/templates/taskapp/view.html:28
#, fuzzy
#| msgid "Time left"
msgid "time left"
msgstr "Времени осталось"
#: taskapp/templates/taskapp/view.html:29
msgid "Task type"
msgstr "Тип задачи"
#: taskapp/views.py:84
msgid "You cannot delete task that assigned to you"
msgstr "Вы не можете удалять назначенные на вас задачи"
#: taskapp/views.py:148
msgid "No responsible employee for the users group"
msgstr "Нет ответственных за группу, в которой находится выбранный абонент"
#: taskapp/views.py:150
msgid "You must select the subscriber"
msgstr "Нужно выбрать абонента"
#: taskapp/views.py:152
msgid "Error in the form fields"
msgstr "Ошибка в полях формы"
#: taskapp/views.py:154
msgid "Employee has not yet signed up for notifications"
msgstr "Исполнитель ещё не подписался на оповещения"
msgid "Tasks to be performed"
msgstr "Задачи, которые необходимо выполнить"
msgid "New tasks"
msgstr "Новые задачи"
msgid "Active tasks"
msgstr "Активные задачи"
msgid "Completed tasks"
msgstr "Выполненные задачи"
msgid "Scheduled tasks me"
msgstr "Назначенные мной задачи"
msgid "All my tasks"
msgstr "Все мои задачи"

15
taskapp/models.py

@ -124,13 +124,14 @@ def task_handler(sender, instance, **kwargs):
)
def task_delete(sender, instance, **kwargs):
ChangeLog.objects.create(
task=instance,
act_type='d',
who=instance.author
)
#def task_delete(sender, instance, **kwargs):
# ChangeLog.objects.create(
# task=instance,
# act_type='d',
# who=instance.author
# )
models.signals.post_save.connect(task_handler, sender=Task)
models.signals.post_delete.connect(task_delete, sender=Task)
#models.signals.post_delete.connect(task_delete, sender=Task)

19
taskapp/views.py

@ -101,7 +101,7 @@ def view(request, task_id):
@only_admins
def task_add_edit(request, task_id=0):
task_id = safe_int(task_id)
uid = request.GET.get('uid')
uid = request.GET.get('uid', 0)
selected_abon = None
frm = TaskFrm()
@ -119,11 +119,8 @@ def task_add_edit(request, task_id=0):
frm = TaskFrm(instance=tsk)
selected_abon = tsk.abon
if uid:
selected_abon = get_object_or_404(Abon, username=str(uid))
if request.method == 'POST':
try:
try:
if request.method == 'POST':
tsk.author = request.user
frm = TaskFrm(request.POST, request.FILES, instance=tsk)
@ -150,8 +147,14 @@ def task_add_edit(request, task_id=0):
messages.error(request, _('You must select the subscriber'))
else:
messages.error(request, _('Error in the form fields'))
except TelegramBot.DoesNotExist:
messages.error(request, _('Employee has not yet signed up for notifications'))
elif uid:
selected_abon = Abon.objects.get(username=str(uid))
except TelegramBot.DoesNotExist:
messages.error(request, _('Employee has not yet signed up for notifications'))
except Abon.DoesNotExist:
messages.warning(request, _("User '%s' does not exist") % str(uid))
except TaskException as e:
messages.error(request, e)
return render(request, 'taskapp/add_edit_task.html', {
'form': frm,

Loading…
Cancel
Save