Browse Source

Fix pays

devel
Dmitry Novikov 7 years ago
parent
commit
295708bce4
  1. 19
      abonapp/admin.py
  2. 32
      abonapp/forms.py
  3. 16
      abonapp/migrations/0009_auto_20181123_1556.py
  4. 80
      abonapp/models.py
  5. 104
      abonapp/pay_systems.py
  6. 5
      abonapp/templates/abonapp/group_list.html
  7. 1
      abonapp/templates/abonapp/invoiceForPayment.html
  8. 192
      abonapp/tests.py
  9. 5
      abonapp/urls.py
  10. 308
      abonapp/views.py
  11. 2
      accounts_app/templatetags/acc_tags.py
  12. 2
      agent/commands/dhcp.py
  13. 2
      clientsideapp/views.py
  14. 2
      devapp/views.py
  15. 2
      dialing_app/views.py
  16. 2
      djing/lib/auth_backends.py
  17. 9
      djing/local_settings.py.example
  18. 15
      djing/settings.py
  19. 3
      djing/urls.py
  20. 0
      finapp/__init__.py
  21. 4
      finapp/admin.py
  22. 5
      finapp/apps.py
  23. 19
      finapp/forms.py
  24. 159
      finapp/locale/ru/LC_MESSAGES/django.po
  25. 71
      finapp/migrations/0001_initial.py
  26. 0
      finapp/migrations/__init__.py
  27. 85
      finapp/models.py
  28. 24
      finapp/templates/finapp/ext.htm
  29. 4
      finapp/templates/finapp/fin_report.html
  30. 53
      finapp/templates/finapp/payHistory.html
  31. 62
      finapp/templates/finapp/payalltimegateway_form.html
  32. 75
      finapp/templates/finapp/payalltimegateway_list.html
  33. 250
      finapp/tests.py
  34. 25
      finapp/urls.py
  35. 222
      finapp/views.py
  36. 2
      gw_app/tests.py
  37. 3
      locale/ru/LC_MESSAGES/django.po
  38. 2
      periodic.py
  39. 1
      requirements.txt
  40. 2
      searchapp/views.py
  41. 2
      taskapp/models.py
  42. 2
      taskapp/views.py
  43. 9
      templates/base.html

19
abonapp/admin.py

@ -1,13 +1,12 @@
from django.contrib import admin
from abonapp.models import generic
from abonapp import models
admin.site.register(generic.Abon)
admin.site.register(generic.InvoiceForPayment)
admin.site.register(generic.AbonLog)
admin.site.register(generic.AbonTariff)
admin.site.register(generic.AbonStreet)
admin.site.register(generic.AllTimePayLog)
admin.site.register(generic.AbonRawPassword)
admin.site.register(generic.PassportInfo)
admin.site.register(generic.AdditionalTelephone)
admin.site.register(models.Abon)
admin.site.register(models.InvoiceForPayment)
admin.site.register(models.AbonLog)
admin.site.register(models.AbonTariff)
admin.site.register(models.AbonStreet)
admin.site.register(models.AbonRawPassword)
admin.site.register(models.PassportInfo)
admin.site.register(models.AdditionalTelephone)

32
abonapp/forms.py

@ -7,7 +7,7 @@ from string import digits, ascii_lowercase
from djing.lib import LogicError
from ip_pool.models import NetworkModel
from gw_app.models import NASModel
from abonapp.models import generic
from abonapp import models
from django.conf import settings
@ -21,12 +21,12 @@ def _generate_random_chars(length=6, chars=digits, split=2, delimiter=''):
)
try:
generic.Abon.objects.get(username=username)
models.Abon.objects.get(username=username)
return _generate_random_chars(
length=length, chars=chars,
split=split, delimiter=delimiter
)
except generic.Abon.DoesNotExist:
except models.Abon.DoesNotExist:
return username
@ -44,11 +44,11 @@ class AbonForm(forms.ModelForm):
super(AbonForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance')
if instance is not None and instance.group is not None:
abon_group_queryset = generic.AbonStreet.objects.filter(
abon_group_queryset = models.AbonStreet.objects.filter(
group=instance.group
)
elif 'group' in self.initial.keys() and self.initial['group'] is not None:
abon_group_queryset = generic.AbonStreet.objects.filter(
abon_group_queryset = models.AbonStreet.objects.filter(
group=self.initial['group']
)
else:
@ -75,7 +75,7 @@ class AbonForm(forms.ModelForm):
)
class Meta:
model = generic.Abon
model = models.Abon
fields = ('username', 'telephone', 'fio', 'group',
'description', 'street', 'house', 'is_active', 'nas')
widgets = {
@ -100,11 +100,11 @@ class AbonForm(forms.ModelForm):
if commit:
acc.save()
try:
abon_raw_passw = generic.AbonRawPassword.objects.get(account=acc)
abon_raw_passw = models.AbonRawPassword.objects.get(account=acc)
abon_raw_passw.passw_text = raw_password
abon_raw_passw.save(update_fields=('passw_text',))
except generic.AbonRawPassword.DoesNotExist:
generic.AbonRawPassword.objects.create(
except models.AbonRawPassword.DoesNotExist:
models.AbonRawPassword.objects.create(
account=acc,
passw_text=raw_password
)
@ -113,7 +113,7 @@ class AbonForm(forms.ModelForm):
class PassportForm(forms.ModelForm):
class Meta:
model = generic.PassportInfo
model = models.PassportInfo
exclude = ('abon',)
widgets = {
'series': forms.TextInput(attrs={
@ -132,7 +132,7 @@ class PassportForm(forms.ModelForm):
class AbonStreetForm(forms.ModelForm):
class Meta:
model = generic.AbonStreet
model = models.AbonStreet
fields = '__all__'
widgets = {
'name': forms.TextInput(attrs={
@ -145,7 +145,7 @@ class AbonStreetForm(forms.ModelForm):
class AdditionalTelephoneForm(forms.ModelForm):
class Meta:
model = generic.AdditionalTelephone
model = models.AdditionalTelephone
exclude = ('abon',)
widgets = {
'telephone': forms.TextInput(attrs={
@ -165,7 +165,7 @@ class AdditionalTelephoneForm(forms.ModelForm):
class PeriodicPayForIdForm(forms.ModelForm):
class Meta:
model = generic.PeriodicPayForId
model = models.PeriodicPayForId
exclude = ('account',)
@ -194,7 +194,7 @@ class ExportUsersForm(forms.Form):
class MarkersForm(forms.ModelForm):
class Meta:
model = generic.Abon
model = models.Abon
fields = 'markers',
def save(self, commit=True):
@ -227,7 +227,7 @@ class AddIpForm(forms.ModelForm):
).first()
if net is not None:
ips = (
ip.ip_address for ip in generic.Abon.objects.filter(
ip.ip_address for ip in models.Abon.objects.filter(
group__in=net.groups.all()
).order_by('ip_address').only(
'ip_address'
@ -245,5 +245,5 @@ class AddIpForm(forms.ModelForm):
)
class Meta:
model = generic.Abon
model = models.Abon
fields = 'ip_address',

16
abonapp/migrations/0009_auto_20181123_1556.py

@ -0,0 +1,16 @@
# Generated by Django 2.1 on 2018-11-23 15:56
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('abonapp', '0008_auto_20181115_1206'),
]
operations = [
migrations.DeleteModel(
name='AllPayLog',
),
]

80
abonapp/models/generic.py → abonapp/models.py

@ -6,7 +6,7 @@ from bitfield import BitField
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 import models, transaction
from django.db.models.signals import post_delete, pre_delete, post_init, \
pre_save
from django.dispatch import receiver
@ -22,8 +22,10 @@ from tariff_app.models import Tariff, PeriodicPay
class AbonLog(models.Model):
abon = models.ForeignKey('Abon', on_delete=models.CASCADE)
amount = models.FloatField(default=0.0)
author = models.ForeignKey(UserProfile, on_delete=models.SET_NULL,
related_name='+', blank=True, null=True)
author = models.ForeignKey(
UserProfile, on_delete=models.SET_NULL,
related_name='+', blank=True, null=True
)
comment = models.CharField(max_length=128)
date = models.DateTimeField(auto_now_add=True)
@ -452,79 +454,9 @@ class InvoiceForPayment(models.Model):
verbose_name_plural = _('Debts')
class AllTimePayLogManager(models.Manager):
@staticmethod
def by_days():
cur = connection.cursor()
cur.execute(
'SELECT SUM(summ) AS alsum, '
'DATE_FORMAT(date_add, "%Y-%m-%d") AS pay_date '
'FROM all_time_pay_log '
'GROUP BY DATE_FORMAT(date_add, "%Y-%m-%d")'
)
while True:
r = cur.fetchone()
if r is None:
break
summ, dat = r
yield {
'summ': summ,
'pay_date': datetime.strptime(dat, '%Y-%m-%d')
}
# Log for pay system "AllTime"
class AllTimePayLog(models.Model):
abon = models.ForeignKey(
Abon,
on_delete=models.SET_DEFAULT,
blank=True,
null=True,
default=None
)
pay_id = models.CharField(
max_length=36,
unique=True,
primary_key=True
)
date_add = models.DateTimeField(auto_now_add=True)
summ = models.FloatField(default=0.0)
trade_point = models.CharField(
_('Trade point'),
max_length=20,
default=None,
null=True,
blank=True
)
receipt_num = models.BigIntegerField(_('Receipt number'), default=0)
objects = AllTimePayLogManager()
def __str__(self):
return self.pay_id
class Meta:
db_table = 'all_time_pay_log'
ordering = ('-date_add',)
# log for all terminals
class AllPayLog(models.Model):
pay_id = models.CharField(max_length=64, primary_key=True)
date_action = models.DateTimeField(auto_now_add=True)
summ = models.FloatField(default=0.0)
pay_system_name = models.CharField(max_length=16)
def __str__(self):
return self.pay_system_name
class Meta:
db_table = 'all_pay_log'
ordering = ('-date_action',)
class AbonRawPassword(models.Model):
account = models.OneToOneField(Abon, models.CASCADE, primary_key=True)
# TODO: make password to EncryptedCharField
passw_text = models.CharField(max_length=64)
def __str__(self):

104
abonapp/pay_systems.py

@ -1,104 +0,0 @@
from hashlib import md5
from django.utils import timezone
from djing.lib import safe_int, safe_float
from .models import Abon, AllTimePayLog
from django.db import DatabaseError
from django.conf import settings
from xmlview.decorators import xml_view
@xml_view(root_node='pay-response')
def allpay(request):
def bad_ret(err_id, err_description=None):
now = timezone.now()
r = {
'status_code': safe_int(err_id),
'time_stamp': now.strftime("%d.%m.%Y %H:%M")
}
if err_description:
r.update({'description': err_description})
return r
try:
serv_id = request.GET.get('SERVICE_ID')
act = safe_int(request.GET.get('ACT'))
pay_account = request.GET.get('PAY_ACCOUNT')
pay_id = request.GET.get('PAY_ID')
pay_amount = safe_float(request.GET.get('PAY_AMOUNT'))
sign = request.GET.get('SIGN').lower()
current_date = timezone.now().strftime("%d.%m.%Y %H:%M")
if act <= 0:
return bad_ret(-101, 'ACT less than zero')
# check sign
md = md5()
s = '_'.join((str(act), pay_account or '', serv_id or '', pay_id, getattr(settings, 'PAY_SECRET')))
md.update(bytes(s, 'utf-8'))
our_sign = md.hexdigest()
if our_sign != sign:
return bad_ret(-101)
if act == 1:
abon = Abon.objects.get(username=pay_account)
fio = abon.fio
ballance = float(abon.ballance)
return {
'balance': ballance,
'name': fio,
'account': pay_account,
'service_id': getattr(settings, 'PAY_SERV_ID'),
'min_amount': 10.0,
'max_amount': 5000,
'status_code': 21,
'time_stamp': current_date
}
elif act == 4:
trade_point = safe_int(request.GET.get('TRADE_POINT'))
receipt_num = safe_int(request.GET.get('RECEIPT_NUM'))
abon = Abon.objects.get(username=pay_account)
pays = AllTimePayLog.objects.filter(pay_id=pay_id)
if pays.count() > 0:
return bad_ret(-100)
abon.add_ballance(None, pay_amount, comment='AllPay %.2f' % pay_amount)
abon.save(update_fields=('ballance',))
AllTimePayLog.objects.create(
pay_id=pay_id,
summ=pay_amount,
abon=abon,
trade_point=trade_point,
receipt_num=receipt_num
)
return {
'pay_id': pay_id,
'service_id': serv_id,
'amount': pay_amount,
'status_code': 22,
'time_stamp': current_date
}
elif act == 7:
pay = AllTimePayLog.objects.get(pay_id=pay_id)
return {
'status_code': 11,
'time_stamp': current_date,
'transaction': {
'pay_id': pay_id,
'service_id': serv_id,
'amount': pay.summ,
'status': 111,
'time_stamp': pay.date_add.strftime("%d.%m.%Y %H:%M")
}
}
else:
return bad_ret(-101, 'ACT is not passed')
except Abon.DoesNotExist:
return bad_ret(-40)
except DatabaseError:
return bad_ret(-90)
except AllTimePayLog.DoesNotExist:
return bad_ret(-10)
except AttributeError:
return bad_ret(-101)

5
abonapp/templates/abonapp/group_list.html

@ -65,11 +65,6 @@
<span class="glyphicon glyphicon-exclamation-sign"></span> <span class="hidden-xs">{% trans 'List of debtors' %}</span>
</a>
{% endif %}
{% if request.user.is_superuser %}
<a href="{% url 'abonapp:fin_report' %}" class="btn btn-default">
<span class="glyphicon glyphicon-usd"></span> <span class="hidden-xs">{% trans 'Fin report' %}</span>
</a>
{% endif %}
<a href="{% url 'abonapp:vcards' %}" target="_blank" class="btn btn-default">
<span class="glyphicon glyphicon-phone"></span>
<span class="hidden-xs">{% trans 'Export vCards' %}</span>

1
abonapp/templates/abonapp/invoiceForPayment.html

@ -6,7 +6,6 @@
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li><a href="{% url 'abonapp:people_list' group.pk %}">{{ group.title }}</a></li>
<li><a href="{% url 'abonapp:abon_phistory' group.pk abon.username %}">{{ abon.fio }}</a></li>
<li class="active">{% trans 'Debts' %}</li>
</ol>
{% endblock %}

192
abonapp/tests.py

@ -6,13 +6,9 @@ from accounts_app.models import UserProfile
from django.shortcuts import resolve_url
from django.test import TestCase, RequestFactory
from django.conf import settings
from django.utils import timezone
from django.utils.html import escape
from django.utils.translation import gettext_lazy as _
from xmltodict import parse
from abonapp.models.generic import Abon, AbonStreet, PassportInfo
from abonapp.pay_systems import allpay
from abonapp.models import Abon, AbonStreet, PassportInfo
from group_app.models import Group
from tariff_app.models import Tariff
from ip_pool.models import NetworkModel
@ -57,192 +53,6 @@ class MyBaseTestCase(metaclass=ABCMeta):
self.group = grp
class AllPayTestCase(MyBaseTestCase, TestCase):
pay_url = '/'
time_format = '%d.%m.%Y %H:%M'
def setUp(self):
a1 = Abon.objects.create_user(
telephone='+79785276481',
username='pay_account1',
password='passw1'
)
a1.ballance = -13.12
a1.fio = 'Test Name'
a1.save(update_fields=('ballance', 'fio'))
# Abon.objects.create_user(
# telephone='+79788163841',
# username='pay_account2',
# password='passw2'
# )
def user_pay_view(self):
print('test_user_pay_view')
current_date = timezone.now().strftime(self.time_format)
service_id = getattr(settings, 'PAY_SERV_ID')
r = allpay(rf.get(self.pay_url, {
'ACT': 1,
'PAY_ACCOUNT': 'pay_account1',
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(1, 'pay_account1', service_id, '840ab457-e7d1-4494-8197-9570da035170')
}
))
r = r.content.decode('utf-8')
o = ''.join((
"<pay-response>",
"<balance>-13.12</balance>",
"<name>Test Name</name>",
"<account>pay_account1</account>",
"<service_id>%s</service_id>" % escape(service_id),
"<min_amount>10.0</min_amount>",
"<max_amount>5000</max_amount>",
"<status_code>21</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"</pay-response>"
))
self.assertXMLEqual(r, o)
def user_pay_pay(self):
print('test_user_pay_pay')
current_date = timezone.now().strftime(self.time_format)
service_id = getattr(settings, 'PAY_SERV_ID')
r = allpay(rf.get(self.pay_url, {
'ACT': 4,
'PAY_ACCOUNT': 'pay_account1',
'PAY_AMOUNT': 18.21,
'RECEIPT_NUM': 2126235,
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(4, 'pay_account1', service_id, '840ab457-e7d1-4494-8197-9570da035170')
}))
r = r.content.decode('utf-8')
xml = ''.join((
"<pay-response>",
"<pay_id>840ab457-e7d1-4494-8197-9570da035170</pay_id>",
"<service_id>%s</service_id>" % escape(service_id),
"<amount>18.21</amount>",
"<status_code>22</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"</pay-response>"
))
self.test_pay_time = current_date
self.assertXMLEqual(r, xml)
def user_pay_check(self):
print('test_user_pay_check')
current_date = timezone.now().strftime(self.time_format)
service_id = getattr(settings, 'PAY_SERV_ID')
r = allpay(rf.get(self.pay_url,
{
'ACT': 7,
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'SIGN': _make_sign(7, '', service_id, '840ab457-e7d1-4494-8197-9570da035170')
}
))
r = r.content.decode('utf-8')
xml = ''.join((
"<pay-response>",
"<status_code>11</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"<transaction>",
"<pay_id>840ab457-e7d1-4494-8197-9570da035170</pay_id>",
"<service_id>%s</service_id>" % escape(service_id),
"<amount>18.21</amount>",
"<status>111</status>",
"<time_stamp>%s</time_stamp>" % escape(self.test_pay_time),
"</transaction>"
"</pay-response>"
))
self.assertXMLEqual(r, xml)
def check_ballance(self):
print('check_ballance')
service_id = getattr(settings, 'PAY_SERV_ID')
r = allpay(rf.get(self.pay_url,
{
'ACT': 1,
'PAY_ACCOUNT': 'pay_account1',
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(1, 'pay_account1', service_id, '840ab457-e7d1-4494-8197-9570da035170')
}
))
r = r.content.decode('utf-8')
r = parse(r)
bl = float(r['pay-response']['balance'])
self.assertEqual(bl, 5.09)
def test_client_does_not_exist(self):
print('test_client_does_not_exist')
current_date = timezone.now().strftime(self.time_format)
service_id = getattr(settings, 'PAY_SERV_ID')
r = allpay(rf.get(self.pay_url, {
'ACT': 1,
'PAY_ACCOUNT': 'not_existing_acc',
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(1, 'not_existing_acc', service_id, '840ab457-e7d1-4494-8197-9570da035170')
}
))
r = r.content.decode('utf-8')
self.assertXMLEqual(r, ''.join((
"<pay-response>",
"<status_code>-40</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"</pay-response>"
)))
def try_pay_double(self):
print('try_pay_double')
service_id = getattr(settings, 'PAY_SERV_ID')
r = allpay(rf.get(self.pay_url, {
'ACT': 4,
'PAY_ACCOUNT': 'pay_account1',
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(4, 'pay_account1', service_id, '840ab457-e7d1-4494-8197-9570da035170')
}))
r = r.content.decode('utf-8')
r = parse(r)
status_code = int(r['pay-response']['status_code'])
self.assertEqual(status_code, -100)
def non_existing_pay(self):
print('non_existing_pay')
current_date = timezone.now().strftime(self.time_format)
uuid = '9f154e93-d800-419a-92f7-da33529138be'
service_id = getattr(settings, 'PAY_SERV_ID')
r = allpay(rf.get(self.pay_url, {
'ACT': 7,
'SERVICE_ID': service_id,
'PAY_ID': uuid,
'SIGN': _make_sign(7, '', service_id, uuid)
}))
r = r.content.decode('utf-8')
xml = ''.join((
"<pay-response>",
"<status_code>-10</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"</pay-response>"
))
self.assertXMLEqual(r, xml)
def test_pays(self):
self.user_pay_view()
self.user_pay_pay()
self.user_pay_check()
self.check_ballance()
self.try_pay_double()
self.non_existing_pay()
class StreetTestCase(MyBaseTestCase, TestCase):
group = None
street = None

5
abonapp/urls.py

@ -50,16 +50,13 @@ group_patterns = [
urlpatterns = [
path('', views.GroupListView.as_view(), name='group_list'),
path('fin_report/', views.fin_report, name='fin_report'),
path('<int:gid>/', include(group_patterns)),
path('log/', views.LogListView.as_view(), name='log'),
path('pay/', views.terminal_pay, name='terminal_pay'),
path('debtors/', views.DebtorsListView.as_view(), name='debtors'),
path('contacts/vcards/', views.vcards, name='vcards'),
# Api's
path('api/abons/', views.abons),
path('api/abon_filter/', views.search_abon),
path('api/dhcp_lever/', views.DhcpLever.as_view()),
path('api/duplicate_pay/', views.DublicatePay.as_view())
path('api/dhcp_lever/', views.DhcpLever.as_view())
]

308
abonapp/views.py

@ -11,14 +11,13 @@ from django.contrib.auth.mixins import LoginRequiredMixin, \
PermissionRequiredMixin as PermissionRequiredMixin_django, \
PermissionRequiredMixin
from django.core.exceptions import PermissionDenied, ValidationError
from django.db import IntegrityError, ProgrammingError, transaction, \
DatabaseError
from django.db import IntegrityError, ProgrammingError, transaction
from django.db.models import Count, Q
from django.http import HttpResponse, HttpResponseBadRequest, \
HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404, resolve_url
from django.urls import reverse_lazy
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _
from django.views.generic import ListView, UpdateView, CreateView, DeleteView
@ -37,9 +36,8 @@ from gw_app.nas_managers import NasFailedResult, NasNetworkError
from ip_pool.models import NetworkModel
from tariff_app.models import Tariff
from taskapp.models import Task
from xmlview.decorators import xml_view
from abonapp import forms
from abonapp.models import generic
from abonapp import models
class PeoplesListView(LoginRequiredMixin, OnlyAdminsMixin,
@ -49,7 +47,7 @@ class PeoplesListView(LoginRequiredMixin, OnlyAdminsMixin,
def get_queryset(self):
street_id = lib.safe_int(self.request.GET.get('street'))
gid = lib.safe_int(self.kwargs.get('gid'))
peoples_list = generic.Abon.objects.filter(group__pk=gid)
peoples_list = models.Abon.objects.filter(group__pk=gid)
if street_id > 0:
peoples_list = peoples_list.filter(street=street_id)
peoples_list = peoples_list.select_related(
@ -75,7 +73,7 @@ class PeoplesListView(LoginRequiredMixin, OnlyAdminsMixin,
context = super(PeoplesListView, self).get_context_data(**kwargs)
context['streets'] = generic.AbonStreet.objects.filter(
context['streets'] = models.AbonStreet.objects.filter(
group=gid
).only('name')
context['street_id'] = lib.safe_int(self.request.GET.get('street'))
@ -104,7 +102,7 @@ class AbonCreateView(LoginRequiredMixin, OnlyAdminsMixin,
group = None
abon = None
form_class = forms.AbonForm
model = generic.Abon
model = models.Abon
template_name = 'abonapp/addAbon.html'
context_object_name = 'group'
@ -161,7 +159,7 @@ class AbonCreateView(LoginRequiredMixin, OnlyAdminsMixin,
class DelAbonDeleteView(LoginAdminMixin, PermissionRequiredMixin, DeleteView):
permission_required = 'abonapp.delete_abon'
model = generic.Abon
model = models.Abon
slug_url_kwarg = 'uname'
slug_field = 'username'
success_url = reverse_lazy('abonapp:group_list')
@ -203,7 +201,7 @@ class DelAbonDeleteView(LoginAdminMixin, PermissionRequiredMixin, DeleteView):
@permission_required('abonapp.can_add_ballance')
@transaction.atomic
def abonamount(request, gid: int, uname):
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
frm = None
try:
if request.method == 'POST':
@ -218,7 +216,7 @@ def abonamount(request, gid: int, uname):
messages.success(
request, _('Account filled successfully on %.2f') % amnt
)
return redirect('abonapp:abon_phistory', gid=gid, uname=uname)
return redirect('abonapp:abon_home', gid=gid, uname=uname)
else:
messages.error(request, _('I not know the account id'))
else:
@ -244,10 +242,10 @@ class DebtsListView(LoginAdminPermissionMixin, OrderedFilteredList):
return self.abon.group
def get_queryset(self):
abon = get_object_or_404(generic.Abon,
abon = get_object_or_404(models.Abon,
username=self.kwargs.get('uname'))
self.abon = abon
return generic.InvoiceForPayment.objects.filter(abon=abon)
return models.InvoiceForPayment.objects.filter(abon=abon)
def get_context_data(self, **kwargs):
context = super(DebtsListView, self).get_context_data(**kwargs)
@ -256,39 +254,13 @@ class DebtsListView(LoginAdminPermissionMixin, OrderedFilteredList):
return context
class PayHistoryListView(LoginAdminPermissionMixin, OrderedFilteredList):
permission_required = 'group_app.view_group'
context_object_name = 'pay_history'
template_name = 'abonapp/payHistory.html'
def get_permission_object(self):
if hasattr(self, 'abon'):
return self.abon.group
return generic.Group.objects.filter(pk=self.kwargs.get('gid')).first()
def get_queryset(self):
abon = get_object_or_404(generic.Abon,
username=self.kwargs.get('uname'))
self.abon = abon
pay_history = generic.AbonLog.objects.filter(
abon=abon
).order_by('-date')
return pay_history
def get_context_data(self, **kwargs):
context = super(PayHistoryListView, self).get_context_data(**kwargs)
context['group'] = self.abon.group
context['abon'] = self.abon
return context
@login_required
@only_admins
def abon_services(request, gid: int, uname):
grp = get_object_or_404(Group, pk=gid)
if not request.user.has_perm('group_app.view_group', grp):
raise PermissionDenied
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
if abon.group != grp:
messages.warning(
@ -298,10 +270,10 @@ def abon_services(request, gid: int, uname):
return redirect('abonapp:abon_services', abon.group.id, abon.username)
try:
periodic_pay = generic.PeriodicPayForId.objects.filter(
periodic_pay = models.PeriodicPayForId.objects.filter(
account=abon
).first()
except generic.PeriodicPayForId.DoesNotExist:
except models.PeriodicPayForId.DoesNotExist:
periodic_pay = None
return render(request, 'abonapp/service.html', {
@ -315,7 +287,7 @@ def abon_services(request, gid: int, uname):
class AbonHomeUpdateView(LoginAdminMixin, PermissionRequiredMixin, UpdateView):
permission_required = 'abonapp.view_abon'
model = generic.Abon
model = models.Abon
form_class = forms.AbonForm
slug_field = 'username'
slug_url_kwarg = 'uname'
@ -370,13 +342,13 @@ class AbonHomeUpdateView(LoginAdminMixin, PermissionRequiredMixin, UpdateView):
if self.initial:
return self.initial
try:
passw = generic.AbonRawPassword.objects.get(
passw = models.AbonRawPassword.objects.get(
account=abon
).passw_text
return {
'password': passw
}
except generic.AbonRawPassword.DoesNotExist:
except models.AbonRawPassword.DoesNotExist:
messages.warning(
self.request,
_('User has not have password, and cannot login')
@ -396,21 +368,11 @@ class AbonHomeUpdateView(LoginAdminMixin, PermissionRequiredMixin, UpdateView):
return super(AbonHomeUpdateView, self).get_context_data(**context)
@transaction.atomic
def terminal_pay(request):
from .pay_systems import allpay
ret_text = allpay(request)
if isinstance(ret_text, HttpResponse):
return ret_text
else:
return HttpResponse(ret_text)
@login_required
@only_admins
@permission_required('abonapp.add_invoiceforpayment')
def add_invoice(request, gid: int, uname: str):
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
grp = get_object_or_404(Group, pk=gid)
try:
@ -418,7 +380,7 @@ def add_invoice(request, gid: int, uname: str):
curr_amount = lib.safe_int(request.POST.get('curr_amount'))
comment = request.POST.get('comment')
newinv = generic.InvoiceForPayment()
newinv = models.InvoiceForPayment()
newinv.abon = abon
newinv.amount = curr_amount
newinv.comment = comment
@ -438,7 +400,7 @@ def add_invoice(request, gid: int, uname: str):
messages.error(request, err)
return render(request, 'abonapp/addInvoice.html', {
'abon': abon,
'invcount': generic.InvoiceForPayment.objects.filter(abon=abon).count(),
'invcount': models.InvoiceForPayment.objects.filter(abon=abon).count(),
'group': grp
})
@ -448,7 +410,7 @@ def add_invoice(request, gid: int, uname: str):
@permission_required('abonapp.can_buy_tariff')
def pick_tariff(request, gid: int, uname):
grp = get_object_or_404(Group, pk=gid)
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
tariffs = Tariff.objects.get_tariffs_by_group(grp.pk)
try:
if request.method == 'POST':
@ -503,7 +465,7 @@ def pick_tariff(request, gid: int, uname):
@permission_required('abonapp.can_complete_service')
def unsubscribe_service(request, gid: int, uname, abon_tariff_id: int):
try:
abon_tariff = get_object_or_404(generic.AbonTariff,
abon_tariff = get_object_or_404(models.AbonTariff,
pk=int(abon_tariff_id))
abon_tariff.delete()
messages.success(request, _('User has been detached from service'))
@ -523,7 +485,7 @@ class LogListView(LoginAdminPermissionMixin, ListView):
http_method_names = ('get',)
context_object_name = 'logs'
template_name = 'abonapp/log.html'
model = generic.AbonLog
model = models.AbonLog
class DebtorsListView(LoginAdminPermissionMixin, ListView):
@ -532,7 +494,7 @@ class DebtorsListView(LoginAdminPermissionMixin, ListView):
http_method_names = ('get',)
context_object_name = 'invoices'
template_name = 'abonapp/debtors.html'
queryset = generic.InvoiceForPayment.objects.filter(status=True)
queryset = models.InvoiceForPayment.objects.filter(status=True)
class TaskLogListView(LoginAdminPermissionMixin, ListView):
@ -546,10 +508,10 @@ class TaskLogListView(LoginAdminPermissionMixin, ListView):
if hasattr(self, 'abon'):
return self.abon.group
else:
return get_object_or_404(generic.Group, pk=self.kwargs.get('gid'))
return get_object_or_404(models.Group, pk=self.kwargs.get('gid'))
def get_queryset(self):
abon = get_object_or_404(generic.Abon,
abon = get_object_or_404(models.Abon,
username=self.kwargs.get('uname'))
self.abon = abon
return Task.objects.filter(abon=abon)
@ -564,17 +526,17 @@ class TaskLogListView(LoginAdminPermissionMixin, ListView):
class PassportUpdateView(LoginAdminPermissionMixin, UpdateView):
permission_required = 'abonapp.view_passportinfo'
form_class = forms.PassportForm
model = generic.PassportInfo
model = models.PassportInfo
template_name = 'abonapp/modal_passport_view.html'
def get_object(self, queryset=None):
self.abon = get_object_or_404(generic.Abon,
self.abon = get_object_or_404(models.Abon,
username=self.kwargs.get('uname'))
try:
passport_instance = generic.PassportInfo.objects.get(
passport_instance = models.PassportInfo.objects.get(
abon=self.abon
)
except generic.PassportInfo.DoesNotExist:
except models.PassportInfo.DoesNotExist:
passport_instance = None
return passport_instance
@ -611,7 +573,7 @@ class PassportUpdateView(LoginAdminPermissionMixin, UpdateView):
class IpUpdateView(LoginAdminPermissionMixin, UpdateView):
permission_required = 'abonapp.change_abon'
form_class = forms.AddIpForm
model = generic.Abon
model = models.Abon
slug_url_kwarg = 'uname'
slug_field = 'username'
template_name = 'abonapp/modal_ip_form.html'
@ -674,7 +636,7 @@ def chgroup_tariff(request, gid):
def dev(request, gid: int, uname):
abon_dev = None
try:
abon = generic.Abon.objects.get(username=uname)
abon = models.Abon.objects.get(username=uname)
if request.method == 'POST':
abon.device = Device.objects.get(pk=request.POST.get('dev'))
abon.save(update_fields=('device',))
@ -687,7 +649,7 @@ def dev(request, gid: int, uname):
request,
_('Device your selected already does not exist')
)
except generic.Abon.DoesNotExist:
except models.Abon.DoesNotExist:
messages.error(request, _('Abon does not exist'))
return redirect('abonapp:people_list', gid=gid)
return render(request, 'abonapp/modal_dev.html', {
@ -703,13 +665,13 @@ def dev(request, gid: int, uname):
@permission_required('group_app.view_group', (Group, 'pk', 'gid'))
def clear_dev(request, gid: int, uname):
try:
abon = generic.Abon.objects.get(username=uname)
abon = models.Abon.objects.get(username=uname)
abon.device = None
abon.dev_port = None
abon.is_dynamic_ip = False
abon.save(update_fields=('device', 'dev_port', 'is_dynamic_ip'))
messages.success(request, _('Device has successfully unattached'))
except generic.Abon.DoesNotExist:
except models.Abon.DoesNotExist:
messages.error(request, _('Abon does not exist'))
return redirect('abonapp:people_list', gid=gid)
return redirect('abonapp:abon_home', gid=gid, uname=uname)
@ -724,7 +686,7 @@ def abon_ping(request, gid: int, uname):
status = False
text = '<span class="glyphicon glyphicon-exclamation-sign"></span> %s' % _(
'no ping')
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
try:
if ip is None:
raise lib.LogicError(_('Ip not passed'))
@ -780,7 +742,7 @@ def abon_ping(request, gid: int, uname):
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(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
abon.autoconnect_service = checked
abon.save(update_fields=('autoconnect_service',))
return {
@ -791,14 +753,14 @@ def set_auto_continue_service(request, gid: int, uname):
@login_required
@only_admins
def vcards(r):
users = generic.Abon.objects.exclude(group=None).select_related(
users = models.Abon.objects.exclude(group=None).select_related(
'group',
'street'
).only(
'username', 'fio', 'group__title', 'telephone',
'street__name', 'house'
)
additional_tels = generic.AdditionalTelephone.objects.select_related(
additional_tels = models.AdditionalTelephone.objects.select_related(
'abon',
'abon__group',
'abon__street'
@ -844,7 +806,7 @@ class DialsListView(LoginRequiredMixin, OnlyAdminsMixin, OrderedFilteredList):
template_name = 'abonapp/dial_log.html'
def get_queryset(self):
abon = get_object_or_404(generic.Abon,
abon = get_object_or_404(models.Abon,
username=self.kwargs.get('uname'))
if not self.request.user.has_perm('group_app.view_group', abon.group):
raise PermissionDenied
@ -853,7 +815,7 @@ class DialsListView(LoginRequiredMixin, OnlyAdminsMixin, OrderedFilteredList):
tel = abon.telephone.replace('+', '')
additional_tels = tuple(
t.telephone for t in
generic.AdditionalTelephone.objects.filter(
models.AdditionalTelephone.objects.filter(
abon=abon
).iterator()
)
@ -904,14 +866,14 @@ def save_user_dev_port(request, gid: int, uname):
is_dynamic_ip = request.POST.get('is_dynamic_ip')
is_dynamic_ip = True if is_dynamic_ip == 'on' else False
try:
abon = generic.Abon.objects.get(username=uname)
abon = models.Abon.objects.get(username=uname)
if user_port == 0:
port = None
else:
port = DevPort.objects.get(pk=user_port)
if abon.device is not None:
try:
other_abon = generic.Abon.objects.get(
other_abon = models.Abon.objects.get(
device=abon.device,
dev_port=port
)
@ -928,9 +890,9 @@ def save_user_dev_port(request, gid: int, uname):
}
)
return redirect('abonapp:abon_home', gid, uname)
except generic.Abon.DoesNotExist:
except models.Abon.DoesNotExist:
pass
except generic.Abon.MultipleObjectsReturned:
except models.Abon.MultipleObjectsReturned:
messages.error(request,
_('Multiple users on the same device port'))
return redirect('devapp:view', abon.device.group.pk,
@ -945,7 +907,7 @@ def save_user_dev_port(request, gid: int, uname):
messages.success(request, _('User port has been saved'))
except DevPort.DoesNotExist:
messages.error(request, _('Selected port does not exist'))
except generic.Abon.DoesNotExist:
except models.Abon.DoesNotExist:
messages.error(request, _('User does not exist'))
return redirect('abonapp:abon_home', gid, uname)
@ -980,17 +942,17 @@ def street_edit(request, gid):
if request.method == 'POST':
for sid, sname in zip(request.POST.getlist('sid'),
request.POST.getlist('sname')):
street = generic.AbonStreet.objects.get(pk=sid)
street = models.AbonStreet.objects.get(pk=sid)
street.name = sname
street.save()
messages.success(request, _('Streets has been saved'))
else:
return render(request, 'abonapp/modal_editstreet.html', {
'gid': gid,
'streets': generic.AbonStreet.objects.filter(group=gid)
'streets': models.AbonStreet.objects.filter(group=gid)
})
except generic.AbonStreet.DoesNotExist:
except models.AbonStreet.DoesNotExist:
messages.error(request, _('One of these streets has not been found'))
return redirect('abonapp:people_list', gid)
@ -1002,9 +964,9 @@ def street_edit(request, gid):
@permission_required('group_app.view_group', (Group, 'pk', 'gid'))
def street_del(request, gid: int, sid: int):
try:
generic.AbonStreet.objects.get(pk=sid, group=gid).delete()
models.AbonStreet.objects.get(pk=sid, group=gid).delete()
messages.success(request, _('The street successfully deleted'))
except generic.AbonStreet.DoesNotExist:
except models.AbonStreet.DoesNotExist:
messages.error(request, _('The street has not been found'))
return redirect('abonapp:people_list', gid)
@ -1024,7 +986,7 @@ def active_nets(request, gid):
@permission_required('abonapp.view_additionaltelephones')
@permission_required('group_app.view_group', (Group, 'pk', 'gid'))
def tels(request, gid: int, uname):
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
telephones = abon.additional_telephones.all()
return render(request, 'abonapp/modal_additional_telephones.html', {
'telephones': telephones,
@ -1041,7 +1003,7 @@ def tel_add(request, gid: int, uname):
frm = forms.AdditionalTelephoneForm(request.POST)
if frm.is_valid():
new_tel = frm.save(commit=False)
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
new_tel.abon = abon
new_tel.save()
messages.success(request, _('New telephone has been saved'))
@ -1063,11 +1025,11 @@ def tel_add(request, gid: int, uname):
def tel_del(request, gid: int, uname):
try:
tid = lib.safe_int(request.GET.get('tid'))
tel = generic.AdditionalTelephone.objects.get(pk=tid)
tel = models.AdditionalTelephone.objects.get(pk=tid)
tel.delete()
messages.success(request,
_('Additional telephone successfully deleted'))
except generic.AdditionalTelephone.DoesNotExist:
except models.AdditionalTelephone.DoesNotExist:
messages.error(request, _('Telephone not found'))
return redirect('abonapp:abon_home', gid, uname)
@ -1077,12 +1039,12 @@ def tel_del(request, gid: int, uname):
@permission_required('group_app.view_group', (Group, 'pk', 'gid'))
def phonebook(request, gid):
res_format = request.GET.get('f')
t1 = generic.Abon.objects.filter(
t1 = models.Abon.objects.filter(
group__id=int(gid)
).only('telephone', 'fio').values_list(
'telephone', 'fio'
)
t2 = generic.AdditionalTelephone.objects.filter(
t2 = models.AdditionalTelephone.objects.filter(
abon__group__id=gid
).only(
'telephone', 'owner_name'
@ -1115,7 +1077,7 @@ def abon_export(request, gid):
if frm.is_valid():
cleaned_data = frm.clean()
fields = cleaned_data.get('fields')
subscribers = generic.Abon.objects.filter(group__id=gid).only(
subscribers = models.Abon.objects.filter(group__id=gid).only(
*fields).values_list(*fields)
if res_format == 'csv':
import csv
@ -1151,26 +1113,6 @@ def abon_export(request, gid):
})
@login_required
@only_admins
def fin_report(request):
q = generic.AllTimePayLog.objects.by_days()
res_format = request.GET.get('f')
if res_format == 'csv':
import csv
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="report.csv"'
writer = csv.writer(response, quoting=csv.QUOTE_NONNUMERIC)
for row in q:
writer.writerow(
(row['summ'], row['pay_date'].strftime('%Y-%m-%d'))
)
return response
return render(request, 'abonapp/fin_report.html', {
'logs': q
})
@login_required
@only_admins
@permission_required('group_app.view_group', (Group, 'pk', 'gid'))
@ -1178,12 +1120,12 @@ def add_edit_periodic_pay(request, gid: int, uname, periodic_pay_id=0):
if periodic_pay_id == 0:
if not request.user.has_perm('abonapp.add_periodicpayforid'):
raise PermissionDenied
periodic_pay_instance = generic.PeriodicPayForId()
periodic_pay_instance = models.PeriodicPayForId()
else:
if not request.user.has_perm('abonapp.change_periodicpayforid'):
raise PermissionDenied
periodic_pay_instance = get_object_or_404(
generic.PeriodicPayForId,
models.PeriodicPayForId,
pk=periodic_pay_id
)
if request.method == 'POST':
@ -1192,7 +1134,7 @@ def add_edit_periodic_pay(request, gid: int, uname, periodic_pay_id=0):
instance=periodic_pay_instance
)
if frm.is_valid():
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
inst = frm.save(commit=False)
inst.account = abon
inst.save()
@ -1215,7 +1157,7 @@ def add_edit_periodic_pay(request, gid: int, uname, periodic_pay_id=0):
@permission_required('abonapp.delete_periodicpayforid')
def del_periodic_pay(request, gid: int, uname, periodic_pay_id):
periodic_pay_instance = get_object_or_404(
generic.PeriodicPayForId,
models.PeriodicPayForId,
pk=periodic_pay_id
)
if periodic_pay_instance.account.username != uname:
@ -1230,7 +1172,7 @@ class EditSibscriberMarkers(LoginAdminPermissionMixin, UpdateView):
http_method_names = ('get', 'post')
template_name = 'abonapp/modal_user_markers.html'
form_class = forms.MarkersForm
model = generic.Abon
model = models.Abon
slug_url_kwarg = 'uname'
slug_field = 'username'
@ -1266,7 +1208,7 @@ class EditSibscriberMarkers(LoginAdminPermissionMixin, UpdateView):
@only_admins
@permission_required('abonapp.change_abon')
def user_session_free(request, gid: int, uname):
abon = get_object_or_404(generic.Abon, username=uname)
abon = get_object_or_404(models.Abon, username=uname)
if abon.nas is None:
messages.error(request, _('gateway required'))
return redirect('abonapp:abon_home', gid, uname)
@ -1286,7 +1228,7 @@ def attach_nas(request, gid):
gateway_id = lib.safe_int(request.POST.get('gateway'))
if gateway_id:
nas = get_object_or_404(NASModel, pk=gateway_id)
abons = generic.Abon.objects.filter(group__id=gid)
abons = models.Abon.objects.filter(group__id=gid)
if abons.exists():
abons.update(nas=nas)
messages.success(
@ -1315,7 +1257,7 @@ def abons(request):
'tarif_id': abn.active_tariff().tariff.pk
if abn.active_tariff() is not None else 0,
'ip': abn.ip_address
} for abn in generic.Abon.objects.iterator())
} for abn in models.Abon.objects.iterator())
tarlist = ({
'id': trf.pk,
@ -1338,7 +1280,7 @@ def search_abon(request):
word = request.GET.get('s')
if not word:
return None
results = generic.Abon.objects.filter(fio__icontains=word)[:8]
results = models.Abon.objects.filter(fio__icontains=word)[:8]
return list(
{'id': usr.pk, 'text': "%s: %s" % (usr.username, usr.fio)}
for usr in results
@ -1398,103 +1340,27 @@ class DhcpLever(SecureApiView):
return str(e)
class DublicatePay(SecureApiView):
http_method_names = 'get',
@staticmethod
def _bad_ret(err_id, err_description=None):
now = timezone.now()
r = {
'status_code': lib.safe_int(err_id),
'time_stamp': now.strftime("%d.%m.%Y %H:%M")
}
if err_description:
r.update({'description': err_description})
return r
@method_decorator(xml_view(root_node='pay-response'))
def get(self, request, *args, **kwargs):
act = lib.safe_int(request.GET.get('ACT'))
self.current_date = timezone.now().strftime("%d.%m.%Y %H:%M")
if act <= 0:
return self._bad_ret(-101, 'ACT less than zero')
try:
if act == 1:
return self._fetch_user_info(request.GET)
elif act == 4:
return self._make_pay(request.GET)
elif act == 7:
return self._check_pay(request.GET)
else:
return self._bad_ret(-101, 'ACT is not passed')
except generic.Abon.DoesNotExist:
return self._bad_ret(-40)
except DatabaseError:
return self._bad_ret(-90)
except generic.AllTimePayLog.DoesNotExist:
return self._bad_ret(-10)
except AttributeError:
return self._bad_ret(-101)
def _fetch_user_info(self, data: dict):
pay_account = data.get('PAY_ACCOUNT')
abon = generic.Abon.objects.get(pk=pay_account)
fio = abon.fio
ballance = float(abon.ballance)
return {
'balance': ballance,
'name': fio,
'account': pay_account,
'service_id': getattr(settings, 'PAY_SERV_ID'),
'min_amount': 10.0,
'max_amount': 5000,
'status_code': 21,
'time_stamp': self.current_date
}
class PayHistoryListView(LoginAdminPermissionMixin, OrderedFilteredList):
permission_required = 'group_app.view_group'
context_object_name = 'pay_history'
template_name = 'abonapp/payHistory.html'
def _make_pay(self, data: dict):
trade_point = lib.safe_int(data.get('TRADE_POINT'))
receipt_num = lib.safe_int(data.get('RECEIPT_NUM'))
pay_account = data.get('PAY_ACCOUNT')
pay_id = data.get('PAY_ID')
pay_amount = lib.safe_float(data.get('PAY_AMOUNT'))
abon = generic.Abon.objects.get(pk=pay_account)
pays = generic.AllTimePayLog.objects.filter(pay_id=pay_id)
if pays.count() > 0:
return self._bad_ret(-100)
abon.add_ballance(None, pay_amount,
comment='KonikaForward %.2f' % pay_amount)
abon.save(update_fields=('ballance',))
def get_permission_object(self):
if hasattr(self, 'abon'):
return self.abon.group
return Group.objects.filter(pk=self.kwargs.get('gid')).first()
generic.AllTimePayLog.objects.create(
pay_id=pay_id,
summ=pay_amount,
abon=abon,
trade_point=trade_point,
receipt_num=receipt_num
)
return {
'pay_id': pay_id,
'service_id': data.get('SERVICE_ID'),
'amount': pay_amount,
'status_code': 22,
'time_stamp': self.current_date
}
def get_queryset(self):
abon = get_object_or_404(models.Abon,
username=self.kwargs.get('uname'))
self.abon = abon
pay_history = models.AbonLog.objects.filter(abon=abon).order_by('-date')
return pay_history
def _check_pay(self, data: dict):
pay_id = data.get('PAY_ID')
pay = generic.AllTimePayLog.objects.get(pay_id=pay_id)
return {
'status_code': 11,
'time_stamp': self.current_date,
'transaction': {
'pay_id': pay_id,
'service_id': data.get('SERVICE_ID'),
'amount': pay.summ,
'status': 111,
'time_stamp': pay.date_add.strftime("%d.%m.%Y %H:%M")
}
def get_context_data(self, **kwargs):
context = {
'group': self.abon.group,
'abon': self.abon
}
context.update(kwargs)
return super(PayHistoryListView, self).get_context_data(**context)

2
accounts_app/templatetags/acc_tags.py

@ -3,7 +3,7 @@ from ipaddress import ip_address, AddressValueError
from django import template
from django.db.models import Model
from django.apps import apps
from abonapp.models.generic import Abon
from abonapp.models import Abon
from six import string_types, class_types
register = template.Library()

2
agent/commands/dhcp.py

@ -1,6 +1,6 @@
from typing import Optional
from django.core.exceptions import MultipleObjectsReturned
from abonapp.models.generic import Abon
from abonapp.models import Abon
from devapp.models import Device, Port

2
clientsideapp/views.py

@ -4,7 +4,7 @@ from django.contrib import messages
from django.db import transaction
from django.utils.translation import gettext_lazy as _, gettext
from abonapp.models.generic import AbonLog, InvoiceForPayment, Abon
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

2
devapp/views.py

@ -1,7 +1,7 @@
import re
from ipaddress import ip_address
from abonapp.models.generic import Abon
from abonapp.models import Abon
from accounts_app.models import UserProfile
from chatbot.models import ChatException
from devapp.base_intr import DeviceImplementationError

2
dialing_app/views.py

@ -12,7 +12,7 @@ from guardian.decorators import permission_required_or_403 as permission_require
from django.db.models import Q
from django.conf import settings
from abonapp.models.generic import Abon
from abonapp.models import Abon
from djing.global_base_views import SecureApiView
from djing import JSONType
from djing.lib import safe_int

2
djing/lib/auth_backends.py

@ -2,7 +2,7 @@ from ipaddress import ip_address, AddressValueError
from django.contrib.auth.backends import ModelBackend
from accounts_app.models import BaseAccount, UserProfile
from abonapp.models.generic import Abon
from abonapp.models import Abon
class CustomAuthBackend(ModelBackend):

9
djing/local_settings.py.template → djing/local_settings.py.example

@ -33,10 +33,6 @@ DATABASES = {
}
}
# service id for AllPay payment system
PAY_SERV_ID = '<service id>'
PAY_SECRET = '<secret>'
# path to asterisk dial records
DIALING_MEDIA = 'path/to/asterisk_records'
@ -69,3 +65,8 @@ EMAIL_HOST = 'smtp.mailserver.com'
EMAIL_PORT = 587
EMAIL_HOST_PASSWORD = 'password'
EMAIL_USE_TLS = True
# Encrypted fields
# https://pypi.org/project/django-encrypted-model-fields/
# You must change this value
#FIELD_ENCRYPTION_KEY = 'vZpDlDPQyU6Ha7NyUGj9uYMuPigejtEPMOZfkYXIQRw='

15
djing/settings.py

@ -41,6 +41,7 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'encrypted_model_fields',
'ip_pool',
'accounts_app',
'gw_app',
@ -49,7 +50,7 @@ INSTALLED_APPS = [
'searchapp',
'devapp',
'mapapp',
'statistics',
'finapp',
'taskapp',
'clientsideapp',
'chatbot',
@ -186,9 +187,6 @@ LOGOUT_URL = reverse_lazy('acc_app:logout')
PAGINATION_ITEMS_PER_PAGE = local_settings.PAGINATION_ITEMS_PER_PAGE
PAY_SERV_ID = local_settings.PAY_SERV_ID
PAY_SECRET = local_settings.PAY_SECRET
DIALING_MEDIA = local_settings.DIALING_MEDIA
DEFAULT_SNMP_PASSWORD = local_settings.DEFAULT_SNMP_PASSWORD
@ -234,3 +232,12 @@ REDIS_PORT = '6379'
BROKER_URL = 'redis://' + REDIS_HOST + ':' + REDIS_PORT + '/0'
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 3600}
CELERY_RESULT_BACKEND = 'redis://' + REDIS_HOST + ':' + REDIS_PORT + '/0'
# Encrypted fields
# https://pypi.org/project/django-encrypted-model-fields/
FIELD_ENCRYPTION_KEY = getattr(
local_settings,
'FIELD_ENCRYPTION_KEY',
'vZpDlDPQyU6Ha7NyUGj9uYMuPigejtEPMOZfkYXIQRw='
)

3
djing/urls.py

@ -18,7 +18,8 @@ urlpatterns = [
path('dialing/', include('dialing_app.urls', namespace='dialapp')),
path('groups/', include('group_app.urls', namespace='group_app')),
path('ip_pool/', include('ip_pool.urls', namespace='ip_pool')),
path('gw/', include('gw_app.urls', namespace='gw_app'))
path('gw/', include('gw_app.urls', namespace='gw_app')),
path('fin/', include('finapp.urls', namespace='finapp'))
# Switch language
#path(r'i18n/', include('django.conf.urls.i18n')),

0
abonapp/models/__init__.py → finapp/__init__.py

4
finapp/admin.py

@ -0,0 +1,4 @@
from django.contrib import admin
from finapp import models
admin.site.register(models.AllTimePayLog)

5
finapp/apps.py

@ -0,0 +1,5 @@
from django.apps import AppConfig
class FinappConfig(AppConfig):
name = 'finapp'

19
finapp/forms.py

@ -0,0 +1,19 @@
from django import forms
from finapp.models import PayAllTimeGateway
class PayAllTimeGatewayForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
instance = getattr(self, 'instance')
if instance and instance.pk:
self.fields['slug'].disabled = True
def clean_slug(self):
if self.instance and self.instance.pk:
return self.instance.slug
return self.data['slug']
class Meta:
model = PayAllTimeGateway
fields = '__all__'

159
finapp/locale/ru/LC_MESSAGES/django.po

@ -0,0 +1,159 @@
# 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, 2018.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-11-27 11:42+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"
#: models.py:32 templates/finapp/payalltimegateway_list.html:22
msgid "Title"
msgstr "Название"
#: models.py:33
msgid "Secret"
msgstr "Секрет"
#: models.py:34 templates/finapp/payalltimegateway_list.html:23
msgid "Service id"
msgstr ""
#: models.py:35
msgid "Slug"
msgstr ""
#: models.py:46
msgid "All time gateway"
msgstr "Платёжный шлюз AllTime"
#: models.py:65 templates/finapp/payHistory.html:24
msgid "Cost"
msgstr "Цена"
#: models.py:67 templates/finapp/payHistory.html:25
msgid "Trade point"
msgstr "Торговая точка"
#: models.py:73 templates/finapp/payHistory.html:26
msgid "Receipt num"
msgstr "Номер квитанции"
#: models.py:75
msgid "Pay gateway"
msgstr "Платёжный шлюз"
#: templates/finapp/fin_report.html:7
msgid "Fin report"
msgstr "Фин. отчёт"
#: templates/finapp/fin_report.html:12
msgid "Money by days"
msgstr "Денег за дни"
#: templates/finapp/fin_report.html:21 templates/finapp/payHistory.html:23
msgid "Date"
msgstr "Дата"
#: templates/finapp/fin_report.html:32
msgid "Pays not found"
msgstr "Платежи не найдены"
#: templates/finapp/fin_report.html:41
msgid "Export to csv"
msgstr "Экспортировать в csv"
#: templates/finapp/payHistory.html:8
#: templates/finapp/payalltimegateway_form.html:7
#: templates/finapp/payalltimegateway_list.html:8
msgid "Payment system"
msgstr "Платёжная система"
#: templates/finapp/payHistory.html:9
msgid "Payment history"
msgstr "История платежей"
#: templates/finapp/payHistory.html:21
msgid "User"
msgstr "Абонент"
#: templates/finapp/payHistory.html:22
msgid "Pay id"
msgstr "ID платежа"
#: templates/finapp/payHistory.html:41
msgid "Payment history is empty"
msgstr "История платежей пуста"
#: templates/finapp/payalltimegateway_form.html:10
msgid "Change payment gateway"
msgstr "Редактировать платёжный шлюз"
#: templates/finapp/payalltimegateway_form.html:12
msgid "Add payment gateway"
msgstr "Добавить платёжный шлюз"
#: templates/finapp/payalltimegateway_form.html:20
msgid "Make new payment gateway"
msgstr "Создать новый платёжный шлюз"
#: templates/finapp/payalltimegateway_form.html:33
msgid "Type info about payment gateway"
msgstr "Укажите данные для платёжной системы"
#: templates/finapp/payalltimegateway_form.html:43
msgid "Save"
msgstr "Сохранить"
#: templates/finapp/payalltimegateway_form.html:47
#: templates/finapp/payalltimegateway_list.html:62
#: templates/finapp/payalltimegateway_list.html:66
msgid "Add"
msgstr "Добвить"
#: templates/finapp/payalltimegateway_form.html:51
msgid "Reset"
msgstr "Сбросить"
#: templates/finapp/payalltimegateway_list.html:13
msgid "List of payment gateways"
msgstr "Список платёжных систем"
#: templates/finapp/payalltimegateway_list.html:24
msgid "Pays count"
msgstr "Количество платежей всего"
#: templates/finapp/payalltimegateway_list.html:36
msgid "Edit"
msgstr "Изменить"
#: templates/finapp/payalltimegateway_list.html:40
msgid "Permission required"
msgstr "Не хватает прав"
#: templates/finapp/payalltimegateway_list.html:53
msgid "Payment gateways not found"
msgstr "Платёжные шлюзы не найдены"
#: views.py:198
msgid "New pay gateway created successfully"
msgstr "Новый платёжный шлюз успешно создан"
#: views.py:221
msgid "Payment gateway successfully updated"
msgstr "Платёжный шлюз успешно обновлён"
msgid "Deleted"
msgstr "Удалён"

71
finapp/migrations/0001_initial.py

@ -0,0 +1,71 @@
# Generated by Django 2.1 on 2018-11-23 15:56
from django.db import migrations, models
import django.db.models.deletion
import encrypted_model_fields.fields
PAY_GW_ID = 0
def make_default_pay_gw(apps, _):
global PAY_GW_ID
PayAllTimeGateway = apps.get_model('finapp.PayAllTimeGateway')
pay_gw = PayAllTimeGateway.objects.first()
if pay_gw is None:
pay_gw = PayAllTimeGateway.objects.create(
title='default',
secret='secret',
service_id='service_id',
slug='default'
)
PAY_GW_ID = pay_gw.pk
class Migration(migrations.Migration):
initial = True
dependencies = [
('abonapp', '0009_auto_20181123_1556'),
]
operations = [
migrations.RunSQL(migrations.RunSQL.noop, state_operations=[
migrations.CreateModel(
name='AllTimePayLog',
fields=[
('pay_id', models.CharField(max_length=36, primary_key=True, serialize=False, unique=True)),
('date_add', models.DateTimeField(auto_now_add=True)),
('summ', models.FloatField(verbose_name='Cost', default=0.0)),
('trade_point', models.CharField(blank=True, default=None, max_length=20, null=True, verbose_name='Trade point')),
('receipt_num', models.BigIntegerField(default=0, verbose_name='Receipt number')),
('abon', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, to='abonapp.Abon')),
],
options={
'db_table': 'all_time_pay_log',
'ordering': ('-date_add',),
},
)
]),
migrations.CreateModel(
name='PayAllTimeGateway',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=64, verbose_name='Title')),
('secret', encrypted_model_fields.fields.EncryptedCharField(verbose_name='Secret')),
('service_id', models.CharField(max_length=64, verbose_name='Service id')),
('slug', models.SlugField(max_length=32, unique=True, verbose_name='Slug')),
],
options={
'verbose_name': 'All time gateway',
'db_table': 'pay_all_time_gateways',
'ordering': ('title',),
},
),
migrations.RunPython(make_default_pay_gw),
migrations.AddField(
model_name='alltimepaylog',
name='pay_gw',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='finapp.PayAllTimeGateway', verbose_name='Pay gateway', default=lambda: PAY_GW_ID),
),
]

0
abonapp/models/payment.py → finapp/migrations/__init__.py

85
finapp/models.py

@ -0,0 +1,85 @@
from datetime import datetime
from django.db import models, connection
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from encrypted_model_fields.fields import EncryptedCharField
from abonapp.models import Abon
class AllTimePayLogManager(models.Manager):
@staticmethod
def by_days():
cur = connection.cursor()
cur.execute(
'SELECT SUM(summ) AS alsum, '
'DATE_FORMAT(date_add, "%Y-%m-%d") AS pay_date '
'FROM all_time_pay_log '
'GROUP BY DATE_FORMAT(date_add, "%Y-%m-%d")'
)
while True:
r = cur.fetchone()
if r is None:
break
summ, dat = r
yield {
'summ': summ,
'pay_date': datetime.strptime(dat, '%Y-%m-%d')
}
class PayAllTimeGateway(models.Model):
title = models.CharField(_('Title'), max_length=64)
secret = EncryptedCharField(verbose_name=_('Secret'), max_length=64)
service_id = models.CharField(_('Service id'), max_length=64)
slug = models.SlugField(_('Slug'), max_length=32,
unique=True, allow_unicode=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('finapp:edit_pay_gw', self.slug)
class Meta:
db_table = 'pay_all_time_gateways'
verbose_name = _('All time gateway')
ordering = 'title',
# Log for pay system "AllTime"
class AllTimePayLog(models.Model):
abon = models.ForeignKey(
Abon,
on_delete=models.SET_DEFAULT,
blank=True,
null=True,
default=None
)
pay_id = models.CharField(
max_length=36,
unique=True,
primary_key=True
)
date_add = models.DateTimeField(auto_now_add=True)
summ = models.FloatField(_('Cost'), default=0.0)
trade_point = models.CharField(
_('Trade point'),
max_length=20,
default=None,
null=True,
blank=True
)
receipt_num = models.BigIntegerField(_('Receipt number'), default=0)
pay_gw = models.ForeignKey(PayAllTimeGateway,
verbose_name=_('Pay gateway'),
on_delete=models.CASCADE)
objects = AllTimePayLogManager()
def __str__(self):
return self.pay_id
class Meta:
db_table = 'all_time_pay_log'
ordering = ('-date_add',)

24
finapp/templates/finapp/ext.htm

@ -0,0 +1,24 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% load i18n %}
{% block breadcrumb %}{% endblock %}
{% block page-header %}
<small>{% trans 'Payment gateways' %}</small>
{% endblock %}
{% block main %}
<ul class="nav nav-tabs nav-justified">
<li class="active">
<a href="#">{% trans 'Payment gateways' %}</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active">
{% block content %}{% endblock %}
</div>
</div>
{% endblock %}

4
abonapp/templates/abonapp/fin_report.html → finapp/templates/finapp/fin_report.html

@ -17,7 +17,7 @@
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>{% trans 'Sum' %}</th>
<th>{% trans 'Cost' %}</th>
<th>{% trans 'Date' %}</th>
</tr>
</thead>
@ -37,7 +37,7 @@
<thead>
<tr>
<td colspan="2">
<a href="{% url 'abonapp:fin_report' %}?f=csv" target="_blank" class="btn btn-sm btn-default">
<a href="{% url 'finapp:fin_report' %}?f=csv" target="_blank" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-download"></span> <span class="hidden-xs">{% trans 'Export to csv' %}</span>
</a>
</td>

53
finapp/templates/finapp/payHistory.html

@ -0,0 +1,53 @@
{% extends 'base.html' %}
{% load i18n %}
{% block breadcrumb %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'finapp:alltime_gateways_list' %}">{% trans 'Payment system' %}</a></li>
<li class="active">{% trans 'Payment history' %}</li>
</ol>
{% endblock %}
{% block page-header %}{{ pay_gw.title }}{% endblock %}
{% block main %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>{% trans 'User' %}</th>
<th>{% trans 'Pay id' %}</th>
<th>{% trans 'Date' %}</th>
<th>{% trans 'Cost' %}</th>
<th>{% trans 'Trade point' %}</th>
<th>{% trans 'Receipt num' %}</th>
</tr>
</thead>
<tbody>
{% for pay in object_list %}
<tr>
<td>
{% if pay.abon %}
<a href="{{ pay.abon.get_absolute_url }}">{{ pay.abon }}</a>
{% else %}
{% trans 'Deleted' %}
{% endif %}
</td>
<td>{{ pay.pay_id }}</td>
<td>{{ pay.date_add|date:'D d E Y H:i:s' }}</td>
<td>{{ pay.summ }}</td>
<td>{{ pay.trade_point|default_if_none:'&mdash;' }}</td>
<td>{{ pay.receipt_num }}</td>
</tr>
{% empty %}
<tr>
<td colspan="6">{% trans 'Payment history is empty' %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

62
finapp/templates/finapp/payalltimegateway_form.html

@ -0,0 +1,62 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% load i18n bootstrap3 %}
{% block breadcrumb %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'finapp:alltime_gateways_list' %}">{% trans 'Payment system' %}</a></li>
<li class="active">
{% if object %}
{% trans 'Change payment gateway' %}
{% else %}
{% trans 'Add payment gateway' %}
{% endif %}
</li>
</ol>
{% endblock %}
{% block page-header %}
{% trans 'Make new payment gateway' %}
{% endblock %}
{% block main %}
{% if object %}
{% url 'finapp:edit_pay_gw' object.slug as form_url %}
{% else %}
{% url 'finapp:add_alltime_gateway' as form_url %}
{% endif %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'Type info about payment gateway' %}</h3>
</div>
<div class="panel-body">
<form role="form" action="{{ form_url }}" method="post">{% csrf_token %}
<div class="form-group">
{% bootstrap_form form %}
</div>
<div class="btn-group btn-group-sm">
{% if object %}
<button type="submit" class="btn btn-primary">
<span class="glyphicon glyphicon-save"></span> {% trans 'Save' %}
</button>
{% else %}
<button type="submit" class="btn btn-success">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %}
</button>
{% endif %}
<button type="reset" class="btn btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Reset' %}
</button>
{% if object %}
<a href="{% url 'finapp:pay_history' object.slug %}" class="btn btn-default">
<span class="glyphicon glyphicon-list"></span> {% trans 'Payment history' %}
</a>
{% endif %}
</div>
</form>
</div>
</div>
{% endblock %}

75
finapp/templates/finapp/payalltimegateway_list.html

@ -0,0 +1,75 @@
{% extends 'base.html' %}
{% load i18n %}
{% block breadcrumb %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li class="active">{% trans 'Payment system' %}</li>
</ol>
{% endblock %}
{% block page-header %}
{% trans 'List of payment gateways' %}
{% endblock %}
{% block main %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th class="col-sm-7">{% trans 'Title' %}</th>
<th class="col-sm-3">{% trans 'Service id' %}</th>
<th class="col-sm-1">{% trans 'Pays count' %}</th>
<th class="col-sm-1"></th>
</tr>
</thead>
<tbody>
{% for gw in object_list %}
<tr>
<td>{{ gw.title }}</td>
<td>{{ gw.service_id }}</td>
<td>{{ gw.pays_count }}</td>
<td class="btn-group btn-group-sm">
{% if perms.finapp.change_payalltimegateway %}
<a href="{% url 'finapp:edit_pay_gw' gw.slug %}" class="btn btn-default" title="{% trans 'Edit' %}" data-toggle="tooltip">
<span class="glyphicon glyphicon-edit"></span>
</a>
{% else %}
<a href="#" class="btn btn-default" title="{% trans 'Permission required' %}" disabled data-toggle="tooltip">
<span class="glyphicon glyphicon-edit"></span>
</a>
{% endif %}
{% if perms.finapp.view_alltimepaylog %}
<a href="{% url 'finapp:pay_history' gw.slug %}" class="btn btn-default" title="{% trans 'Payment history' %}" data-toggle="tooltip">
<span class="glyphicon glyphicon-list"></span>
</a>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="4">{% trans 'Payment gateways not found' %}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="4" class="btn-group btn-group-sm">
{% if perms.finapp.add_payalltimegateway %}
<a href="{% url 'finapp:add_alltime_gateway' %}" class="btn btn-default">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %}
</a>
{% else %}
<a href="#" class="btn btn-default" title="{% trans 'Permission required' %}" disabled>
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %}
</a>
{% endif %}
</td>
</tr>
</tfoot>
</table>
{% endblock %}

250
finapp/tests.py

@ -0,0 +1,250 @@
from abc import ABCMeta
from hashlib import md5
from django.shortcuts import resolve_url
from django.test import TestCase
from django.utils import timezone
from django.utils.html import escape
from xmltodict import parse
from abonapp.models import Abon
from accounts_app.models import UserProfile
from djing import settings
from finapp.models import PayAllTimeGateway
from group_app.models import Group
def _make_sign(act: int, pay_account: str, serv_id: str, pay_id, secret: str):
md = md5()
s = "%d_%s_%s_%s_%s" % (act, pay_account, serv_id, pay_id, secret)
md.update(bytes(s, 'utf-8'))
return md.hexdigest()
class MyBaseTestCase(metaclass=ABCMeta):
def _client_get_check_login(self, url):
"""
Checks if url is protected from unauthorized access
:param url:
:return: authorized response
"""
r = self.client.get(url)
self.assertRedirects(r, "%s?next=%s" % (getattr(settings, 'LOGIN_URL'), url))
self.client.force_login(self.adminuser)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
return r
def setUp(self):
grp = Group.objects.create(title='Grp1')
a1 = Abon.objects.create_user(
telephone='+79781234567',
username='abon',
password='passw1'
)
a1.group = grp
a1.save(update_fields=('group',))
my_admin = UserProfile.objects.create_superuser('+79781234567', 'local_superuser', 'ps')
self.adminuser = my_admin
self.abon = a1
self.group = grp
class AllPayTestCase(MyBaseTestCase, TestCase):
time_format = '%d.%m.%Y %H:%M'
def setUp(self):
a1 = Abon.objects.create_user(
telephone='+79785276481',
username='pay_account1',
password='passw1'
)
a1.ballance = -13.12
a1.fio = 'Test Name'
a1.save(update_fields=('ballance', 'fio'))
pay_system = PayAllTimeGateway.objects.create(
title='Test pay system',
secret='secret',
service_id='service_id',
slug='pay_gw_slug'
)
self.pay_system = pay_system
def user_pay_view(self):
print('test_user_pay_view')
current_date = timezone.now().strftime(self.time_format)
url = resolve_url('finapp:all_time_pay', self.pay_system.slug)
service_id = self.pay_system.service_id
r = self.client.get(url, {
'ACT': 1,
'PAY_ACCOUNT': 'pay_account1',
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(1, 'pay_account1', service_id,
'840ab457-e7d1-4494-8197-9570da035170', self.pay_system.secret)
}
)
r = r.content.decode('utf-8')
o = ''.join((
"<pay-response>",
"<balance>-13.12</balance>",
"<name>Test Name</name>",
"<account>pay_account1</account>",
"<service_id>%s</service_id>" % escape(service_id),
"<min_amount>10.0</min_amount>",
"<max_amount>5000</max_amount>",
"<status_code>21</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"</pay-response>"
))
self.assertXMLEqual(r, o)
def user_pay_pay(self):
print('test_user_pay_pay')
current_date = timezone.now().strftime(self.time_format)
url = resolve_url('finapp:all_time_pay', self.pay_system.slug)
service_id = self.pay_system.service_id
r = self.client.get(url, {
'ACT': 4,
'PAY_ACCOUNT': 'pay_account1',
'PAY_AMOUNT': 18.21,
'RECEIPT_NUM': 2126235,
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(4, 'pay_account1', service_id,
'840ab457-e7d1-4494-8197-9570da035170', self.pay_system.secret)
})
r = r.content.decode('utf-8')
xml = ''.join((
"<pay-response>",
"<pay_id>840ab457-e7d1-4494-8197-9570da035170</pay_id>",
"<service_id>%s</service_id>" % escape(service_id),
"<amount>18.21</amount>",
"<status_code>22</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"</pay-response>"
))
self.test_pay_time = current_date
self.assertXMLEqual(r, xml)
def user_pay_check(self):
print('test_user_pay_check')
current_date = timezone.now().strftime(self.time_format)
url = resolve_url('finapp:all_time_pay', self.pay_system.slug)
service_id = self.pay_system.service_id
r = self.client.get(url,
{
'ACT': 7,
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'SIGN': _make_sign(7, '', service_id,
'840ab457-e7d1-4494-8197-9570da035170', self.pay_system.secret)
}
)
r = r.content.decode('utf-8')
xml = ''.join((
"<pay-response>",
"<status_code>11</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"<transaction>",
"<pay_id>840ab457-e7d1-4494-8197-9570da035170</pay_id>",
"<service_id>%s</service_id>" % escape(service_id),
"<amount>18.21</amount>",
"<status>111</status>",
"<time_stamp>%s</time_stamp>" % escape(self.test_pay_time),
"</transaction>"
"</pay-response>"
))
self.assertXMLEqual(r, xml)
def check_ballance(self):
print('check_ballance')
url = resolve_url('finapp:all_time_pay', self.pay_system.slug)
service_id = self.pay_system.service_id
r = self.client.get(url,
{
'ACT': 1,
'PAY_ACCOUNT': 'pay_account1',
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(1, 'pay_account1', service_id,
'840ab457-e7d1-4494-8197-9570da035170', self.pay_system.secret)
}
)
r = r.content.decode('utf-8')
r = parse(r)
bl = float(r['pay-response']['balance'])
self.assertEqual(bl, 5.09)
def test_client_does_not_exist(self):
print('test_client_does_not_exist')
current_date = timezone.now().strftime(self.time_format)
url = resolve_url('finapp:all_time_pay', self.pay_system.slug)
service_id = self.pay_system.service_id
r = self.client.get(url, {
'ACT': 1,
'PAY_ACCOUNT': 'not_existing_acc',
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(1, 'not_existing_acc', service_id,
'840ab457-e7d1-4494-8197-9570da035170', self.pay_system.secret)
})
r = r.content.decode('utf-8')
self.assertXMLEqual(r, ''.join((
"<pay-response>",
"<status_code>-40</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"<description>Account does not exist</description>",
"</pay-response>"
)))
def try_pay_double(self):
print('try_pay_double')
url = resolve_url('finapp:all_time_pay', self.pay_system.slug)
service_id = self.pay_system.service_id
r = self.client.get(url, {
'ACT': 4,
'PAY_ACCOUNT': 'pay_account1',
'SERVICE_ID': service_id,
'PAY_ID': '840ab457-e7d1-4494-8197-9570da035170',
'TRADE_POINT': 'term1',
'SIGN': _make_sign(4, 'pay_account1', service_id,
'840ab457-e7d1-4494-8197-9570da035170', self.pay_system.secret)
})
r = r.content.decode('utf-8')
r = parse(r)
status_code = int(r['pay-response']['status_code'])
self.assertEqual(status_code, -100)
def non_existing_pay(self):
print('non_existing_pay')
current_date = timezone.now().strftime(self.time_format)
uuid = '9f154e93-d800-419a-92f7-da33529138be'
url = resolve_url('finapp:all_time_pay', self.pay_system.slug)
service_id = self.pay_system.service_id
r = self.client.get(url, {
'ACT': 7,
'SERVICE_ID': service_id,
'PAY_ID': uuid,
'SIGN': _make_sign(7, '', service_id, uuid, self.pay_system.secret)
})
r = r.content.decode('utf-8')
xml = ''.join((
"<pay-response>",
"<status_code>-10</status_code>",
"<time_stamp>%s</time_stamp>" % escape(current_date),
"</pay-response>"
))
self.assertXMLEqual(r, xml)
def test_pays(self):
self.user_pay_view()
self.user_pay_pay()
self.user_pay_check()
self.check_ballance()
self.try_pay_double()
self.non_existing_pay()

25
finapp/urls.py

@ -0,0 +1,25 @@
from django.urls import path
from finapp import views
app_name = 'finapp'
urlpatterns = [
path('', views.AllTimeGatewaysListView.as_view(),
name='alltime_gateways_list'),
# path('fin_report/', views.BasicFinReport.as_view(), name='fin_report'),
# path('pay/', views.terminal_pay, name='terminal_pay'),
path('add/', views.AddAllTimeGateway.as_view(),
name='add_alltime_gateway'),
path('<slug:pay_slug>/pay_history/', views.PayHistoryListView.as_view(),
name='pay_history'),
path('<slug:pay_slug>/make_pay/', views.AllTimePay.as_view(),
name='all_time_pay'),
path('<slug:pay_slug>/edit/', views.EditPayUpdateView.as_view(),
name='edit_pay_gw'),
]

222
finapp/views.py

@ -0,0 +1,222 @@
import csv
from hashlib import md5
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db import DatabaseError
from django.db.models import Count
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, resolve_url
from django.urls import reverse_lazy
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.utils.translation import ugettext_lazy as _
from xmlview.decorators import xml_view
from djing import lib
from djing.global_base_views import OrderedFilteredList
from djing.lib import safe_int
from djing.lib.mixins import LoginAdminMixin, LoginAdminPermissionMixin
from finapp.forms import PayAllTimeGatewayForm
from finapp.models import AllTimePayLog, PayAllTimeGateway
from abonapp.models import Abon
class AllTimePay(DetailView):
http_method_names = 'get',
model = PayAllTimeGateway
pk_url_kwarg = 'slug'
slug_url_kwarg = 'pay_slug'
@staticmethod
def _bad_ret(err_id, err_description=None):
now = timezone.now()
r = {
'status_code': lib.safe_int(err_id),
'time_stamp': now.strftime("%d.%m.%Y %H:%M")
}
if err_description:
r.update({'description': err_description})
return r
def check_sign(self, data: dict, sign: str) -> bool:
act = safe_int(data.get('ACT'))
pay_account = data.get('PAY_ACCOUNT')
serv_id = data.get('SERVICE_ID')
pay_id = data.get('PAY_ID')
md = md5()
s = '_'.join(
(str(act), pay_account or '', serv_id or '',
pay_id, self.object.secret)
)
md.update(bytes(s, 'utf-8'))
our_sign = md.hexdigest()
return our_sign == sign
@method_decorator(xml_view(root_node='pay-response'))
def get(self, request, *args, **kwargs):
self.object = self.get_object()
act = lib.safe_int(request.GET.get('ACT'))
self.current_date = timezone.now().strftime("%d.%m.%Y %H:%M")
if act <= 0:
return self._bad_ret(-101, 'ACT must be more than 0')
if not self.check_sign(request.GET, request.GET.get('SIGN').lower()):
self._bad_ret(-101, 'Bad sign')
try:
if act == 1:
return self._fetch_user_info(request.GET)
elif act == 4:
return self._make_pay(request.GET)
elif act == 7:
return self._check_pay(request.GET)
else:
return self._bad_ret(-101, 'ACT is not passed')
except Abon.DoesNotExist:
return self._bad_ret(-40, 'Account does not exist')
except DatabaseError:
return self._bad_ret(-90)
except AllTimePayLog.DoesNotExist:
return self._bad_ret(-10)
except AttributeError:
return self._bad_ret(-101)
def _fetch_user_info(self, data: dict):
pay_account = data.get('PAY_ACCOUNT')
abon = Abon.objects.get(username=pay_account)
fio = abon.fio
ballance = float(abon.ballance)
return {
'balance': ballance,
'name': fio,
'account': pay_account,
'service_id': self.object.service_id,
'min_amount': 10.0,
'max_amount': 5000,
'status_code': 21,
'time_stamp': self.current_date
}
def _make_pay(self, data: dict):
trade_point = lib.safe_int(data.get('TRADE_POINT'))
receipt_num = lib.safe_int(data.get('RECEIPT_NUM'))
pay_account = data.get('PAY_ACCOUNT')
pay_id = data.get('PAY_ID')
pay_amount = lib.safe_float(data.get('PAY_AMOUNT'))
abon = Abon.objects.get(username=pay_account)
pays = AllTimePayLog.objects.filter(pay_id=pay_id)
if pays.exists():
return self._bad_ret(-100, 'Pay already exists')
abon.add_ballance(
None, pay_amount,
comment='%s %.2f' % (self.object.title, pay_amount)
)
abon.save(update_fields=('ballance',))
AllTimePayLog.objects.create(
pay_id=pay_id,
summ=pay_amount,
abon=abon,
trade_point=trade_point,
receipt_num=receipt_num,
pay_gw=self.object
)
return {
'pay_id': pay_id,
'service_id': data.get('SERVICE_ID'),
'amount': pay_amount,
'status_code': 22,
'time_stamp': self.current_date
}
def _check_pay(self, data: dict):
pay_id = data.get('PAY_ID')
pay = AllTimePayLog.objects.get(pay_id=pay_id)
return {
'status_code': 11,
'time_stamp': self.current_date,
'transaction': {
'pay_id': pay_id,
'service_id': data.get('SERVICE_ID'),
'amount': pay.summ,
'status': 111,
'time_stamp': pay.date_add.strftime("%d.%m.%Y %H:%M")
}
}
class BasicFinReport(LoginAdminMixin, ListView):
model = AllTimePayLog
queryset = AllTimePayLog.objects.by_days()
template_name = 'finapp/fin_report.html'
context_object_name = 'logs'
def get(self, request, *args, **kwargs):
res_format = request.GET.get('f')
if res_format == 'csv':
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="report.csv"'
writer = csv.writer(response, quoting=csv.QUOTE_NONNUMERIC)
for row in self.object_list:
writer.writerow(
(row['summ'], row['pay_date'].strftime('%Y-%m-%d'))
)
return response
return super().get(request, *args, **kwargs)
class PayHistoryListView(LoginAdminMixin, PermissionRequiredMixin,
OrderedFilteredList):
permission_required = 'group_app.view_group'
context_object_name = 'pay_history'
template_name = 'finapp/payHistory.html'
model = AllTimePayLog
def get_queryset(self):
pay_history = AllTimePayLog.objects.filter(
pay_gw__slug=self.kwargs.get('pay_slug')
).order_by('-date_add')
return pay_history
def get_context_data(self, **kwargs):
context = {
'pay_gw': get_object_or_404(PayAllTimeGateway, slug=self.kwargs.get('pay_slug'))
}
context.update(kwargs)
return super(PayHistoryListView, self).get_context_data(**context)
class AddAllTimeGateway(LoginAdminMixin, PermissionRequiredMixin, CreateView):
permission_required = 'finapp.add_payalltimegateway'
model = PayAllTimeGateway
form_class = PayAllTimeGatewayForm
success_url = reverse_lazy('finapp:alltime_gateways_list')
def form_valid(self, form):
messages.success(self.request, _('New pay gateway created successfully'))
return super(AddAllTimeGateway, self).form_valid(form)
class AllTimeGatewaysListView(LoginAdminPermissionMixin, ListView):
permission_required = 'finapp.view_payalltimegateway'
model = PayAllTimeGateway
queryset = PayAllTimeGateway.objects.annotate(
pays_count=Count('alltimepaylog')
)
class EditPayUpdateView(LoginAdminPermissionMixin, UpdateView):
permission_required = 'finapp.change_payalltimegateway'
model = PayAllTimeGateway
form_class = PayAllTimeGatewayForm
pk_url_kwarg = 'slug'
slug_url_kwarg = 'pay_slug'
def get_success_url(self):
return resolve_url('finapp:edit_pay_gw', self.object.slug)
def form_valid(self, form):
messages.success(self.request, _('Payment gateway successfully updated'))
return super(EditPayUpdateView, self).form_valid(form)

2
gw_app/tests.py

@ -1,6 +1,6 @@
from abc import ABCMeta
from abonapp.models.generic import Abon
from abonapp.models import Abon
from accounts_app.models import UserProfile
from django.conf import settings
from django.shortcuts import resolve_url

3
locale/ru/LC_MESSAGES/django.po

@ -125,3 +125,6 @@ msgstr "На сервере произошла ошибка. Пожалуйст
msgid "Are you sure about them?"
msgstr "Вы уверены в этом?"
msgid "Finance"
msgstr "Финансы"

2
periodic.py

@ -8,7 +8,7 @@ django.setup()
from django.utils import timezone
from django.db import transaction
from django.db.models import signals, Count
from abonapp.models.generic import Abon, AbonTariff, abontariff_pre_delete, \
from abonapp.models import Abon, AbonTariff, abontariff_pre_delete, \
PeriodicPayForId, AbonLog
from gw_app.nas_managers import NasNetworkError, NasFailedResult
from gw_app.models import NASModel

1
requirements.txt

@ -25,6 +25,7 @@ pyst2
django-bitfield
transliterate
asterisk
django-encrypted-model-fields
# django-xmlview for pay system allpay
-e git://github.com/nerosketch/django-xmlview.git#egg=django-xmlview

2
searchapp/views.py

@ -2,7 +2,7 @@ import re
from django.db.models import Q
from django.shortcuts import render
from django.utils.html import escape
from abonapp.models.generic import Abon
from abonapp.models import Abon
from devapp.models import Device
from djing import MAC_ADDR_REGEX
from django.contrib.auth.decorators import login_required

2
taskapp/models.py

@ -6,7 +6,7 @@ from django.conf import settings
from django.shortcuts import resolve_url
from django.utils import timezone
from django.utils.translation import ugettext as _
from abonapp.models.generic import Abon
from abonapp.models import Abon
from .handle import handle as task_handle
TASK_PRIORITIES = (

2
taskapp/views.py

@ -14,7 +14,7 @@ from django.views.generic.edit import FormMixin, DeleteView, UpdateView
from guardian.decorators import permission_required_or_403 as permission_required
from chatbot.models import MessageQueue
from abonapp.models.generic import Abon
from abonapp.models import Abon
from djing import httpresponse_to_referrer
from djing.lib import safe_int, MultipleException, RuTimedelta
from djing.lib.decorators import only_admins, json_view

9
templates/base.html

@ -62,6 +62,15 @@
</a>
</li>
{% if perms.fonapp.view_payalltimegateway %}
{% url 'finapp:alltime_gateways_list' as finhome %}
<li{% if finhome in request.path %} class="active"{% endif %}>
<a href="{{ finhome }}">
<span class="glyphicon glyphicon-credit-card"></span> {% trans 'Finance' %}
</a>
</li>
{% endif %}
{% url 'ip_pool:networks' as ippool_home %}
<li{% if ippool_home in request.path %} class="active"{% endif %}>
<a href="{{ ippool_home }}">

Loading…
Cancel
Save