Browse Source

Make new functionality. Add flag Abon.autoconnect_service, if it checked then service may connect automatically when old service is expired.

devel
Dmitry Novikov 8 years ago
parent
commit
073c98887c
  1. 3
      abonapp/locale/ru/LC_MESSAGES/django.po
  2. 44
      abonapp/migrations/0004_auto_20180918_1734.py
  3. 55
      abonapp/models.py
  4. 109
      abonapp/templates/abonapp/service.html
  5. 3
      abonapp/urls.py
  6. 15
      abonapp/views.py
  7. 45
      clientsideapp/locale/ru/LC_MESSAGES/django.po
  8. 11
      clientsideapp/templates/clientsideapp/services.html
  9. 3
      clientsideapp/urls.py
  10. 15
      clientsideapp/views.py
  11. 39
      periodic.py
  12. 6
      static/clientside/my_clientside.js
  13. 6
      static/js/my.js

3
abonapp/locale/ru/LC_MESSAGES/django.po

@ -1153,3 +1153,6 @@ msgstr "Отмена"
msgid "View"
msgstr "Открыть"
msgid "Auto continue service."
msgstr "Автопродление услуги."

44
abonapp/migrations/0004_auto_20180918_1734.py

@ -0,0 +1,44 @@
# Generated by Django 2.1 on 2018-09-18 17:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('abonapp', '0003_abon_nas'),
]
operations = [
migrations.AlterModelOptions(
name='abon',
options={'ordering': ('fio',), 'permissions': (('can_buy_tariff', 'Buy service perm'), ('can_add_ballance', 'fill account'), ('can_ping', 'Can ping')), 'verbose_name': 'Abon', 'verbose_name_plural': 'Abons'},
),
migrations.AlterModelOptions(
name='abonlog',
options={'ordering': ('-date',)},
),
migrations.AlterModelOptions(
name='additionaltelephone',
options={'ordering': ('owner_name',), 'verbose_name': 'Additional telephone', 'verbose_name_plural': 'Additional telephones'},
),
migrations.AlterModelOptions(
name='invoiceforpayment',
options={'ordering': ('date_create',), 'verbose_name': 'Debt', 'verbose_name_plural': 'Debts'},
),
migrations.AddField(
model_name='abon',
name='autoconnect_service',
field=models.BooleanField(default=False, verbose_name='Automatically connect next service'),
),
migrations.AlterField(
model_name='abon',
name='is_dynamic_ip',
field=models.BooleanField(default=False, verbose_name='Is dynamic ip'),
),
migrations.AlterField(
model_name='passportinfo',
name='date_of_acceptance',
field=models.DateField(verbose_name='Date of acceptance'),
),
]

55
abonapp/models.py

@ -6,7 +6,7 @@ from django.conf import settings
from django.core import validators
from django.core.validators import RegexValidator
from django.db import models, connection, transaction
from django.db.models.signals import post_delete, pre_delete, post_init
from django.db.models.signals import post_delete, pre_delete, post_init, pre_save
from django.dispatch import receiver
from django.shortcuts import resolve_url
from django.utils import timezone
@ -87,7 +87,7 @@ class AbonManager(MyUserManager):
class Abon(BaseAccount):
current_tariff = models.ForeignKey(AbonTariff, null=True, blank=True, on_delete=models.SET_NULL)
current_tariff = models.OneToOneField(AbonTariff, null=True, blank=True, on_delete=models.SET_NULL)
group = models.ForeignKey(Group, on_delete=models.SET_NULL, blank=True, null=True, verbose_name=_('User group'))
ballance = models.FloatField(default=0.0)
ip_addresses = models.ManyToManyField(IpLeaseModel, verbose_name=_('Ip addresses'))
@ -96,9 +96,10 @@ class Abon(BaseAccount):
house = models.CharField(_('House'), max_length=12, null=True, blank=True)
device = models.ForeignKey('devapp.Device', null=True, blank=True, on_delete=models.SET_NULL)
dev_port = models.ForeignKey('devapp.Port', null=True, blank=True, on_delete=models.SET_NULL)
is_dynamic_ip = models.BooleanField(default=False)
is_dynamic_ip = models.BooleanField(_('Is dynamic ip'), default=False)
nas = models.ForeignKey('nas_app.NASModel', null=True, blank=True, on_delete=models.SET_NULL,
verbose_name=_('Network access server'), default=None)
autoconnect_service = models.BooleanField(_('Automatically connect next service'), default=False)
MARKER_FLAGS = (
('icon_donkey', _('Donkey')),
@ -148,7 +149,16 @@ class Abon(BaseAccount):
)
self.ballance += amount
def pick_tariff(self, tariff, author, comment=None, deadline=None):
def pick_tariff(self, tariff, author, comment=None, deadline=None) -> None:
"""
Trying to buy a service if enough money.
:param tariff: instance of tariff_app.models.Tariff.
:param author: Instance of accounts_app.models.UserProfile. Who connected this
service. May be None if author is a system.
:param comment: Optional text for logging this pay.
:param deadline: Instance of datetime.datetime. Date when service is expired.
:return: Nothing
"""
if not isinstance(tariff, Tariff):
raise TypeError
@ -170,22 +180,23 @@ class Abon(BaseAccount):
if self.ballance < amount:
raise LogicError(_('not enough money'))
new_abtar = AbonTariff.objects.create(
deadline=deadline, tariff=tariff
)
self.current_tariff = new_abtar
with transaction.atomic():
new_abtar = AbonTariff.objects.create(
deadline=deadline, tariff=tariff
)
self.current_tariff = new_abtar
# charge for the service
self.ballance -= amount
# charge for the service
self.ballance -= amount
self.save()
self.save(update_fields=('ballance', 'current_tariff'))
# make log about it
AbonLog.objects.create(
abon=self, amount=-tariff.amount,
author=author,
comment=comment or _('Buy service default log')
)
# make log about it
AbonLog.objects.create(
abon=self, amount=-tariff.amount,
author=author,
comment=comment or _('Buy service default log')
)
# Destroy the service if the time has come
# def bill_service(self, author):
@ -468,8 +479,16 @@ def abon_tariff_post_init(sender, **kwargs):
abon_tariff = kwargs["instance"]
if getattr(abon_tariff, 'time_start') is None:
abon_tariff.time_start = timezone.now()
calc_obj = abon_tariff.tariff.get_calc_type()(abon_tariff)
if getattr(abon_tariff, 'deadline') is None:
calc_obj = abon_tariff.tariff.get_calc_type()(abon_tariff)
abon_tariff.deadline = calc_obj.calc_deadline()
@receiver(pre_save, sender=AbonTariff)
def abon_tariff_pre_save(sender, **kwargs):
abon_tariff = kwargs["instance"]
if getattr(abon_tariff, 'deadline') is None:
calc_obj = abon_tariff.tariff.get_calc_type()(abon_tariff)
abon_tariff.deadline = calc_obj.calc_deadline()

109
abonapp/templates/abonapp/service.html

@ -3,6 +3,58 @@
{% block content %}
<div class="row">
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'Services for buy' %}</h3>
</div>
<div class="panel-body">
<table class="table table-condensed">
<thead>
<tr>
<th>{% trans 'Pick a service' %}</th>
<th>{% trans 'Service' %}</th>
<th>{% trans 'Price' %}</th>
<th>{% trans 'Speed In' %}</th>
<th>{% trans 'Speed Out' %}</th>
</tr>
</thead>
<tbody>
{% with can_ch_trf=perms.tariff_app.change_tariff %}
{% for service in services %}
<tr>
<td><a href="{% url 'abonapp:pick_tariff' group.pk abon.username %}?selected_tariff={{ service.pk }}"
class="btn btn-sm btn-default" title="{{ service.get_calc_type_display }}" data-toggle="tooltip"{% if abon_tariff %} disabled{% endif %}>
<span class="glyphicon glyphicon-shopping-cart"></span>
</a></td>
<td>
{% if can_ch_trf %}
<a href="{% url 'tarifs:edit' service.pk %}" title="{{ service.descr }}" data-toggle="tooltip"><b>{{ service.title }}</b></a>
{% else %}
{{ service.title }}
{% endif %}
</td>
<td>{{ service.amount }} {% trans 'currency' %}</td>
<td>{{ service.speedIn }}</td>
<td>{{ service.speedOut }}</td>
</tr>
{% empty %}
<tr><td colspan="5">
{% trans 'This group has no services' %}
<a href="{% url 'abonapp:ch_group_tariff' group.pk %}" class="btn btn-sm btn-default" title="{% trans 'User groups' %}">
<span class="glyphicon glyphicon-cog"></span> {% trans 'Tariffs in groups' %}
</a>
</td></tr>
{% endfor %}
{% endwith %}
</tbody>
</table>
<a href="{% url 'abonapp:ch_group_tariff' group.pk %}" class="btn btn-sm btn-primary" title="{% trans 'User groups' %}">
<span class="glyphicon glyphicon-cog"></span> {% trans 'Attach services to group' %}
</a>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="panel panel-default">
@ -44,6 +96,10 @@
</dl>
<blockquote>
<p>
{% trans 'Auto continue service.' %}
<input type="checkbox" data-url="{% url 'abonapp:set_auto_continue_service' group.pk abon.username %}" class="autosave" {{ abon.autoconnect_service|yesno:'checked,' }}>
</p>
<p>{{ abon_tariff.tariff.descr }}</p>
</blockquote>
@ -68,58 +124,6 @@
</div>
</div>
</div>
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'Services for buy' %}</h3>
</div>
<div class="panel-body">
<table class="table table-condensed">
<thead>
<tr>
<th>{% trans 'Pick a service' %}</th>
<th>{% trans 'Service' %}</th>
<th>{% trans 'Price' %}</th>
<th>{% trans 'Speed In' %}</th>
<th>{% trans 'Speed Out' %}</th>
</tr>
</thead>
<tbody>
{% with can_ch_trf=perms.tariff_app.change_tariff %}
{% for service in services %}
<tr>
<td><a href="{% url 'abonapp:pick_tariff' group.pk abon.username %}?selected_tariff={{ service.pk }}"
class="btn btn-sm btn-default" title="{{ service.get_calc_type_display }}" data-toggle="tooltip"{% if abon_tariff %} disabled{% endif %}>
<span class="glyphicon glyphicon-shopping-cart"></span>
</a></td>
<td>
{% if can_ch_trf %}
<a href="{% url 'tarifs:edit' service.pk %}" title="{{ service.descr }}" data-toggle="tooltip"><b>{{ service.title }}</b></a>
{% else %}
{{ service.title }}
{% endif %}
</td>
<td>{{ service.amount }} {% trans 'currency' %}</td>
<td>{{ service.speedIn }}</td>
<td>{{ service.speedOut }}</td>
</tr>
{% empty %}
<tr><td colspan="5">
{% trans 'This group has no services' %}
<a href="{% url 'abonapp:ch_group_tariff' group.pk %}" class="btn btn-sm btn-default" title="{% trans 'User groups' %}">
<span class="glyphicon glyphicon-cog"></span> {% trans 'Tariffs in groups' %}
</a>
</td></tr>
{% endfor %}
{% endwith %}
</tbody>
</table>
<a href="{% url 'abonapp:ch_group_tariff' group.pk %}" class="btn btn-sm btn-primary" title="{% trans 'User groups' %}">
<span class="glyphicon glyphicon-cog"></span> {% trans 'Attach services to group' %}
</a>
</div>
</div>
</div>
{% if perms.tariff_app.view_periodic_pay %}
<div class="col-sm-6">
@ -149,6 +153,7 @@
</div>
</div>
{% endif %}
</div>
{% endblock %}

3
abonapp/urls.py

@ -32,7 +32,8 @@ subscriber_patterns = [
path('periodic_pay/<int:periodic_pay_id>/', views.add_edit_periodic_pay, name='add_periodic_pay'),
path('periodic_pay/<int:periodic_pay_id>/del/', views.del_periodic_pay, name='del_periodic_pay'),
path('lease/add/', views.lease_add, name='lease_add'),
path('ping/', views.abon_ping, name='ping')
path('ping/', views.abon_ping, name='ping'),
path('set_auto_continue_service/', views.set_auto_continue_service, name='set_auto_continue_service')
]
group_patterns = [

15
abonapp/views.py

@ -408,7 +408,6 @@ def add_invoice(request, gid: int, uname: str):
@login_required
@only_admins
@permission_required('abonapp.can_buy_tariff')
@transaction.atomic
def pick_tariff(request, gid: int, uname):
grp = get_object_or_404(Group, pk=gid)
abon = get_object_or_404(models.Abon, username=uname)
@ -719,6 +718,20 @@ def abon_ping(request, gid: int, uname):
}
@login_required
@only_admins
@json_view
def set_auto_continue_service(request, gid: int, uname):
checked = request.GET.get('checked')
checked = True if checked == 'true' else False
abon = get_object_or_404(models.Abon, username=uname)
abon.autoconnect_service = checked
abon.save(update_fields=('autoconnect_service',))
return {
'status': 0
}
@login_required
@only_admins
def vcards(r):

45
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: 2018-08-09 14:57+0300\n"
"POT-Creation-Date: 2018-09-18 15:18+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n"
"Language: ru\n"
@ -59,7 +59,7 @@ msgid "Your debt"
msgstr "Ваши долги"
#: templates/clientsideapp/debts.html:11
#: templates/clientsideapp/tasklist.html:14
#: templates/clientsideapp/tasklist.html:13
msgid "State"
msgstr "Состояние"
@ -72,7 +72,7 @@ msgid "Description"
msgstr "Описание"
#: templates/clientsideapp/debts.html:14
#: templates/clientsideapp/tasklist.html:15
#: templates/clientsideapp/tasklist.html:14
msgid "Date of create"
msgstr "Дата создания"
@ -87,7 +87,7 @@ msgstr "Оплатить"
#: templates/clientsideapp/debts.html:23 templates/clientsideapp/ext.html:77
#: templates/clientsideapp/modal_service_buy.html:19
#: templates/clientsideapp/services.html:26
#: templates/clientsideapp/services.html:55
#: templates/clientsideapp/services.html:66
msgid "currency"
msgstr "руб."
@ -195,6 +195,8 @@ msgid ""
"Inbound speed: %(speedIn)s MBit/s<br> Outgoing speed: %(speedOut)s MBit/"
"s<br> Cost: %(amount)s rubles."
msgstr ""
"Входящая скорость: %(speedIn)s MBit/s<br> Исходяшая скорость: %(speedOut)s "
"MBit/s<br> Стоимость: %(amount)s руб."
#: templates/clientsideapp/modal_service_buy.html:19
#, python-format
@ -202,7 +204,7 @@ msgid "The cost is %(amount)s"
msgstr "Стоимость %(amount)s"
#: templates/clientsideapp/modal_service_buy.html:23
#: templates/clientsideapp/services.html:63
#: templates/clientsideapp/services.html:74
msgid "Pick"
msgstr "Заказать"
@ -246,7 +248,26 @@ msgstr "Дата завершения услуги"
msgid "Cost"
msgstr "Стоимость"
#: templates/clientsideapp/services.html:35
#: templates/clientsideapp/services.html:28
msgid "Auto continue service."
msgstr "Автопродление услуги."
#: templates/clientsideapp/services.html:33
msgid ""
"The check box <b>Auto continue service</b> for auto-renewal service is "
"designed so that the following <u>automatically</u> connected to the service "
"that you had last month. Connection will occur if the account has enough "
"funds.</p> <p>If you do not have time to make a Deposit before the service "
"ended, replenish your account and log back into your personal account to "
"connect it.</p>"
msgstr ""
"<p>Флажок <b>Автопрдление услуги</b> предназначен для того чтоб в следующем "
"месяце <u>автоматически</u> подключилась услуга которая была у вас в прошлом "
"месяце. Подключение произойдёт если на счету достаточно средств.</p> <p>Если "
"вы не успели внести средства до того как закочилась услуга, пополните счёт и "
"снова войдите в личный кабинет чтоб подключить её.</p>"
#: templates/clientsideapp/services.html:46
msgid ""
"<strong>Attantion!</strong> You have not yet a service, for use the services "
"please purchase service you want."
@ -254,27 +275,27 @@ msgstr ""
"<strong>Внимание!</strong> У вас нет услуги, для использования ресурсов "
"приобретите нужную услугу из представленных тут."
#: templates/clientsideapp/services.html:46
#: templates/clientsideapp/services.html:57
msgid "Services available for ordering"
msgstr "Доступные для заказа услуги"
#: templates/clientsideapp/services.html:68
#: templates/clientsideapp/services.html:79
msgid "No services available for ordering"
msgstr "Нет доступных для заказа услуг"
#: templates/clientsideapp/tasklist.html:7
#: templates/clientsideapp/tasklist.html:6
msgid "Task history"
msgstr "История заявок"
#: templates/clientsideapp/tasklist.html:16
#: templates/clientsideapp/tasklist.html:15
msgid "The nature of the damage"
msgstr "Характер заявки"
#: templates/clientsideapp/tasklist.html:17
#: templates/clientsideapp/tasklist.html:16
msgid "Expected or real completion date"
msgstr "Ожидаемый или реальный срок выполнения"
#: templates/clientsideapp/tasklist.html:43
#: templates/clientsideapp/tasklist.html:42
msgid "You didn't leave any requests for breakdowns."
msgstr "Заявки по вашей учётной записи не найдены"

11
clientsideapp/templates/clientsideapp/services.html

@ -24,8 +24,19 @@
<dt>{% trans 'Cost' %}</dt>
<dd>{{ current_service.tariff.amount }} {% trans 'currency' %}</dd>
<dt>{% trans 'Auto continue service.' %}</dt>
<dd><input type="checkbox" data-url="{% url 'clientsideapp:set_auto_continue_service' %}" class="autosave" {{ request.user.autoconnect_service|yesno:'checked,' }}></dd>
</dl>
<p>{{ current_service.tariff.descr }}</p>
{% blocktrans trimmed %}
The check box <b>Auto continue service</b> for auto-renewal service
is designed so that the following <u>automatically</u> connected to the service
that you had last month. Connection will occur if the account has enough funds.</p>
<p>If you do not have time to make a Deposit before the service ended,
replenish your account and log back into your personal account to connect it.</p>
{% endblocktrans %}
</div>
</div>

3
clientsideapp/urls.py

@ -10,5 +10,6 @@ urlpatterns = [
path('services/<int:srv_id>/buy/', views.buy_service, name='buy_service'),
path('debts/', views.debts_list, name='debts'),
path('debts/<int:d_id>/', views.debt_buy, name='debt_buy'),
path('tasks/', views.task_history, name='task_history')
path('tasks/', views.task_history, name='task_history'),
path('set_auto_continue_service/', views.set_auto_continue_service, name='set_auto_continue_service')
]

15
clientsideapp/views.py

@ -5,6 +5,7 @@ from django.db import transaction
from django.utils.translation import gettext_lazy as _, gettext
from abonapp.models import AbonLog, InvoiceForPayment, Abon
from djing.lib.decorators import json_view
from tariff_app.models import Tariff
from taskapp.models import Task
from djing.lib import LogicError
@ -43,7 +44,6 @@ def services(request):
@login_required
@transaction.atomic
def buy_service(request, srv_id):
abon = request.user
service = get_object_or_404(Tariff, pk=srv_id)
@ -115,3 +115,16 @@ def task_history(request):
return render(request, 'clientsideapp/tasklist.html', {
'tasks': tasks
})
@login_required
@json_view
def set_auto_continue_service(request):
checked = request.GET.get('checked')
checked = True if checked == 'true' else False
abon = request.user
abon.autoconnect_service = checked
abon.save(update_fields=('autoconnect_service',))
return {
'status': 0
}

39
periodic.py

@ -41,7 +41,8 @@ def main():
AbonTariff.objects.filter(abon=None).delete()
now = timezone.now()
fields = ('id', 'tariff__title', 'abon__id')
expired_services = AbonTariff.objects.filter(deadline__lt=now).exclude(abon=None)
expired_services = AbonTariff.objects.exclude(abon=None).filter(deadline__lt=now,
abon__autoconnect_service=False)
# finishing expires services
with transaction.atomic():
@ -57,6 +58,42 @@ def main():
)
print(log)
expired_services.delete()
# Automatically connect new service
for ex in AbonTariff.objects.filter(deadline__lt=now, abon__autoconnect_service=True).exclude(
abon=None).iterator():
abon = ex.abon
trf = ex.tariff
amount = round(trf.amount, 2)
if abon.ballance >= amount:
# can continue service
with transaction.atomic():
abon.ballance -= amount
ex.time_start = now
ex.deadline = None # Deadline sets automatically in signal pre_save
ex.save(update_fields=('time_start', 'deadline'))
abon.save(update_fields=('ballance',))
# make log about it
l = AbonLog.objects.create(
abon=abon, amount=-amount,
comment="Автоматическое продление услуги '%s'" % trf.title
)
print(l.comment)
else:
# finish service
with transaction.atomic():
ex.delete()
l = AbonLog.objects.create(
abon_id=ex.abon.id,
amount=0,
author=None,
date=now,
comment="Срок действия услуги '%(service_name)s' истёк" % {
'service_name': ex.tariff.title
}
)
print(l.comment)
signals.pre_delete.connect(abontariff_pre_delete, sender=AbonTariff)
# manage periodic pays

6
static/clientside/my_clientside.js

@ -40,6 +40,12 @@ $(document).ready(function () {
}
});
// autosave checkbox
$('input[type=checkbox].autosave').on('click', function(){
var data_url = $(this).attr('data-url');
$.getJSON(data_url, {checked: this.checked});
});
$('.btn-modal').on('click', function(){
$.get(this.href, function(r){
show_ModalMyContent(r);

6
static/js/my.js

@ -297,6 +297,12 @@ $(document).ready(function () {
return false;
});
// autosave checkbox
$('input[type=checkbox].autosave').on('click', function(){
var data_url = $(this).attr('data-url');
$.getJSON(data_url, {checked: this.checked});
});
$('button.player-btn').aplayer();
$('[data-toggle="tooltip"]').tooltip({container:'body'});

Loading…
Cancel
Save