Browse Source

Теперь дата завершения услуги расчитывается при подключении услуги

devel
bashmak 9 years ago
parent
commit
e2bee3aee2
  1. 66
      abonapp/models.py
  2. 11
      abonapp/views.py
  3. 6
      tariff_app/base_intr.py
  4. 34
      tariff_app/custom_tariffs.py
  5. 2
      tariff_app/models.py
  6. 4
      templates/abonapp/activate_service.html

66
abonapp/models.py

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from django.utils import timezone
from django.utils.datetime_safe import datetime
from django.db import models
from django.core.validators import DecimalValidator
from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult
@ -10,14 +9,7 @@ from accounts_app.models import UserProfile
class LogicError(Exception):
def __init__(self, value):
self.message = value
def __str__(self):
return repr(self.message)
def __str__(self):
return repr(self.message)
pass
class AbonGroup(models.Model):
@ -56,6 +48,9 @@ class AbonTariff(models.Model):
# время начала действия, остальные что не начали действие - NULL
time_start = models.DateTimeField(null=True, blank=True, default=None)
# время завершения услуги
deadline = models.DateTimeField(null=True, blank=True, default=None)
def priority_up(self):
# ищем услугу с большим приоритетом(число приоритета меньше)
target_abtar = AbonTariff.objects.filter(
@ -108,21 +103,24 @@ class AbonTariff(models.Model):
# Считает текущую стоимость услуг согласно выбранной для тарифа логики оплаты (см. в документации)
def calc_amount_service(self):
calc_obj = self.tariff.get_calc_type()
calc_obj = self.tariff.get_calc_type()(self)
# calc_obj - instance of tariff_app.custom_tariffs.TariffBase
amount = calc_obj.calc_amount(self)
amount = calc_obj.calc_amount()
return round(amount, 2)
# Активируем тариф
def activate(self, current_user):
calc_obj = self.tariff.get_calc_type()(self)
amnt = self.calc_amount_service()
# если не хватает денег
if self.abon.ballance < amnt:
raise LogicError('Не хватает денег на счету')
# дата активации услуги
# считаем дату активации услуги
self.time_start = timezone.now()
# считаем дату завершения услуги
self.deadline = calc_obj.calc_deadline()
# снимаем деньги за услугу
self.abon.make_pay(current_user, amnt)
self.abon.make_pay(current_user, amnt, u_comment='Завершение и оплата услуги по истечению срока действия')
self.save()
# Используется-ли услуга сейчас, если время старта есть то он активирован
@ -209,7 +207,7 @@ class Abon(UserProfile):
self.ballance += amount
# покупаем тариф
def buy_tariff(self, tariff, author, comment=None):
def pick_tariff(self, tariff, author, comment=None):
assert isinstance(tariff, Tariff)
# выбераем связь ТарифАбонент с самым низким приоритетом
@ -241,47 +239,29 @@ class Abon(UserProfile):
def activate_next_tariff(self, author):
ats = AbonTariff.objects.filter(abon=self).order_by('tariff_priority')
nw = datetime.now(tz=timezone.get_current_timezone())
nw = timezone.datetime.now()
for at in ats:
# Если активированный тариф
if not at.is_started():
return
# время к началу месяца
to_start_month = datetime(nw.year, nw.month, 1, tzinfo=timezone.get_current_timezone())
# проверяем расстояние от Сегодня до начала этого месяца.
# И от заказа тарифа до начала этого месяца
if (nw - at.time_start) > (nw - to_start_month):
# Заказ из прошлого месяца, срок действия закончен
print('Заказ из прошлого месяца, срок действия закончен')
# если услуга просрочена
if nw > at.deadline:
print("Услуга просрочена, отключаем, и подключаем новую")
# выберем следующую по приоритету
# next_tarifs = AbonTariff.objects.filter(tariff_priority__gt = self.tariff_priority, abon=self.abon)
next_tarifs = filter(lambda tr: tr.tariff_priority > at.tariff_priority, ats)[:2]
next_tarifs = [tr for tr in ats if tr.tariff_priority > at.tariff_priority][:2]
#next_tarifs = filter(lambda tr: tr.tariff_priority > at.tariff_priority, ats)[:2]
# и если что-нибудь вернулось то активируем, давая время начала действия
# и если что-нибудь из списка следующих услуг вернулось - то активируем
if len(next_tarifs) > 0:
next_tarifs[0].time_start = nw
next_tarifs[0].save(update_fields=['time_start'])
next_tarifs[0].activate(author)
# завершаем текущую услугу.
# удаляем запись о текущей услугу.
at.delete()
# Создаём лог о завершении услуги
AbonLog.objects.create(
abon=self,
amount=0,
author=author,
comment='Завершение услуги по истечению срока действия'
)
# есть-ли доступ у абонента к услуге, смотрим в tariff_app.custom_tariffs.<TariffBase>.manage_access()
def is_access(self):
trf = self.active_tariff()
if not trf: return False
ct = trf.get_calc_type()
ct = trf.get_calc_type()()
if ct.manage_access(self):
return True
else:
@ -311,7 +291,7 @@ class InvoiceForPayment(models.Model):
author = models.ForeignKey(UserProfile, related_name='+')
def __str__(self):
return "%s -> %d $" % (self.abon.username, self.amount)
return "%s -> %.2f" % (self.abon.username, self.amount)
def set_ok(self):
self.status = True

11
abonapp/views.py

@ -285,6 +285,7 @@ def abonhome(request, gid, uid):
})
@mydefs.require_ssl
def terminal_pay(request):
from .pay_systems import allpay
ret_text = allpay(request)
@ -329,7 +330,7 @@ def add_invoice(request, gid, uid):
@login_required
@permission_required('abonapp.can_buy_tariff')
def buy_tariff(request, gid, uid):
def pick_tariff(request, gid, uid):
frm = None
grp = get_object_or_404(models.AbonGroup, id=gid)
abon = get_object_or_404(models.Abon, id=uid)
@ -338,7 +339,7 @@ def buy_tariff(request, gid, uid):
frm = forms.BuyTariff(request.POST)
if frm.is_valid():
cd = frm.cleaned_data
abon.buy_tariff(cd['tariff'], request.user)
abon.pick_tariff(cd['tariff'], request.user)
#abon.save()
messages.success(request, 'Тариф успешно выбран')
return redirect('abonapp:abon_services', gid=gid, uid=abon.id)
@ -433,7 +434,7 @@ def activate_service(request, gid, uid, srvid):
abtar.activate(request.user)
messages.success(request, 'Услуга активирована')
return redirect('abonapp:abon_home', gid, uid)
return redirect('abonapp:abon_services', gid, uid)
except NasFailedResult as e:
messages.error(request, e)
@ -441,12 +442,14 @@ def activate_service(request, gid, uid, srvid):
messages.warning(request, e)
except models.LogicError as e:
messages.error(request, e)
calc_obj = abtar.tariff.get_calc_type()(abtar)
return render(request, 'abonapp/activate_service.html', {
'abon': abtar.abon,
'abon_group': abtar.abon.group,
'abtar': abtar,
'amount': amount,
'diff': abtar.abon.ballance - amount
'diff': abtar.abon.ballance - amount,
'deadline': calc_obj.calc_deadline()
})

6
tariff_app/base_intr.py

@ -5,12 +5,12 @@ from abc import ABCMeta, abstractmethod
class TariffBase(metaclass=ABCMeta):
@abstractmethod
def calc_amount(self, abon_tariff):
def calc_amount(self):
"""Считает итоговую сумму платежа"""
@abstractmethod
def get_avail_time(self):
"""Возвращает оставшееся время услуги в секундах"""
def calc_deadline(self):
"""Считаем дату, до которой действкет тариф"""
@staticmethod
def description():

34
tariff_app/custom_tariffs.py

@ -1,42 +1,46 @@
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from datetime import timedelta
from django.utils import timezone
from .base_intr import TariffBase
from calendar import monthrange
# from abonapp import AbonTariff
class TariffDefault(TariffBase):
# Базовый функционал считает стоимость пропорционально использованному времени
def calc_amount(self, abon_tariff):
def __init__(self, abon_tariff):
#assert isinstance(abon_tariff, AbonTariff)
self.abon_tariff = abon_tariff
# Базовый функционал считает стоимость пропорционально использованному времени
def calc_amount(self):
# сейчас
nw = timezone.now()
# сколько прошло с начала действия услуги
# если времени начала нет то это начало действия, использованное время 0
time_diff = nw - abon_tariff.time_start if abon_tariff.time_start else timedelta(0)
time_diff = nw - self.abon_tariff.time_start if self.abon_tariff.time_start else timedelta(0)
# времени в этом месяце
curr_month_time = datetime(nw.year, nw.month if nw.month == 12 else nw.month + 1, 1) - timedelta(days=1)
curr_month_time = timezone.datetime(nw.year, nw.month if nw.month == 12 else nw.month + 1, 1) - timedelta(days=1)
curr_month_time = timedelta(days=curr_month_time.day)
# Сколько это в процентах от всего месяца (k - коеффициент)
k = time_diff.total_seconds() / curr_month_time.total_seconds()
# результат - это полная стоимость тарифа умноженная на k
res = k * abon_tariff.tariff.amount
res = k * self.abon_tariff.tariff.amount
return float(res)
# возвращаем сколько времени осталось до завершения услуги (конца месяца)
def get_avail_time(self):
from calendar import monthrange
# Тут мы расчитываем конец действия услуги, завершение будет в конце месяца
def calc_deadline(self):
nw = timezone.now()
last_day = monthrange(nw.year, nw.month)[1]
last_month_date = datetime(year=nw.year, month=nw.month, day=last_day,
hour=23,minute=59, second=59,tzinfo=nw.tzinfo)
return last_month_date - nw
last_month_date = timezone.datetime(year=nw.year, month=nw.month, day=last_day,
hour=23, minute=59, second=59)
return timezone.make_aware(last_month_date)
@staticmethod
def description():
@ -47,8 +51,8 @@ class TariffDp(TariffDefault):
# в IS снимается вся стоимость тарифа вне зависимости от времени использования
# просто возвращаем всю стоимость тарифа
def calc_amount(self, abon_tariff):
return float(abon_tariff.tariff.amount)
def calc_amount(self):
return float(self.abon_tariff.tariff.amount)
@staticmethod
def description():
@ -56,7 +60,7 @@ class TariffDp(TariffDefault):
class TariffCp(TariffDefault):
def calc_amount(self, abon_tariff):
def calc_amount(self):
return 12.6
@staticmethod

2
tariff_app/models.py

@ -28,7 +28,7 @@ class Tariff(models.Model):
if len(ob) > 0:
res_type = ob[0][1]
assert issubclass(res_type, TariffBase)
return res_type()
return res_type
def __str__(self):
return "%s (%.2f)" % (self.title, self.amount)

4
templates/abonapp/activate_service.html

@ -24,7 +24,9 @@
<p>Вы уверены что хотите активировать абоненту эту услугу?<br>
Обратите внимание что с его счёта <b>снимутся деньги</b> и откроется доступ к ресурсам оплаченной
услуги.<br>
Стоимость услуги: {{ amount }}руб. На счету {{ abon.ballance }} руб, останется {{ diff }} руб.</p>
Стоимость услуги: {{ amount }}руб. На счету {{ abon.ballance }} руб, останется {{ diff }} руб.<br>
Услуга будет действовать до {{ deadline|date:'d F Y, H:i:s' }}
</p>
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Подтвердить

Loading…
Cancel
Save