diff --git a/BaseModels/base_models.py b/BaseModels/base_models.py index 21b5a4a..adc86f7 100644 --- a/BaseModels/base_models.py +++ b/BaseModels/base_models.py @@ -18,7 +18,7 @@ from django.contrib.contenttypes.fields import GenericRelation # add_introspection_rules([], ["^tinymce\.models\.HTMLField"]) class BaseModel(models.Model): - name = models.TextField(verbose_name=_('Название'), + name = models.TextField(verbose_name=_("Название"), help_text=_('Название'), null=True, blank=True) name_plural = models.TextField(verbose_name=_('Название (множественное число)'), null=True, blank=True) diff --git a/BaseModels/pay_systems/DVL_Group_kaz/api/funcs.py b/BaseModels/pay_systems/DVL_Group_kaz/api/funcs.py index 9bbe71e..ced9986 100644 --- a/BaseModels/pay_systems/DVL_Group_kaz/api/funcs.py +++ b/BaseModels/pay_systems/DVL_Group_kaz/api/funcs.py @@ -1,20 +1,100 @@ +import json + import requests +from requests_pkcs12 import get,post +pkcs12_filename = 'dvldigitalprojects.p12' +pkcs12_password = 'QNlhRStcY7mB' + + +def get_domain_url(): + return 'https://sandboxapi.paymtech.kz/' + +def get_kwargs_for_request(): + return { + 'headers': { + 'content-type': 'application/json', + }, + 'auth': ('dvldigitalprojects', 'aPqSRVZhxFjjSqbB'), + 'pkcs12_filename': pkcs12_filename, + 'pkcs12_password': pkcs12_password + } def ping(): - req_str = f'https://developerhub.alfabank.by:8273/partner/1.0.1/public/nationalRates{code_str}{date_str}' + url = f'{get_domain_url()}ping' data = {} - headers = { - 'content-type': 'application/json' - } try: - msg = f'GET {req_str}' + msg = f'GET {url}' print(msg) - res = requests.get(req_str, data=data, headers=headers) + res = get( + url, + **get_kwargs_for_request() + ) + msg = f'answer received = {str(res)}' print(msg) except Exception as e: - msg = f'Exception GET {req_str} = {str(e)} ({str(res)})' + msg = f'Exception GET {url} = {str(e)} ({str(res)})' print(msg) - res = None \ No newline at end of file + res = None + return False + + return True + + +def get_order_status(bank_order_id): + + url = f'{get_domain_url()}orders/{str(bank_order_id)}' + + res = None + + data = { + 'expand': [ + 'card', 'client', 'location', 'custom_fields', + 'issuer', 'secure3d', 'operations', 'cashflow' + ] + } + + try: + msg = f'GET {url}' + print(msg) + res = get( + url, + data=json.dumps(data), + **get_kwargs_for_request() + ) + + msg = f'create_order answer received = {str(res)}' + print(msg) + except Exception as e: + msg = f'Exception create_order GET {url} = {str(e)} ({str(res)})' + print(msg) + res = None + + return res + + +def create_order(data): + + url = f'{get_domain_url()}orders/create' + + res = None + + try: + msg = f'POST {url}' + print(msg) + res = post( + url, + data=json.dumps(data), + **get_kwargs_for_request() + ) + + msg = f'create_order answer received = {str(res)}' + print(msg) + except Exception as e: + msg = f'Exception create_order POST {url} = {str(e)} ({str(res)})' + print(msg) + res = None + + return res \ No newline at end of file diff --git a/BillingApp/__init__.py b/BillingApp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BillingApp/admin.py b/BillingApp/admin.py new file mode 100644 index 0000000..0027da2 --- /dev/null +++ b/BillingApp/admin.py @@ -0,0 +1,37 @@ +from sets.admin import * +from .models import * +from django.contrib import admin + +class Admin_SubscribeOrder(Admin_BaseModel): + + fieldsets = ( + (None, { + 'classes': ['wide'], + 'fields': ( + ('user', 'subscribe', 'subscribe_for_user'), + ('enable', 'order'), + ('sum', 'currency'), + ('status', 'last_operation_status'), + ('bank_order_id', 'pay_page'), + ) + }), + ) + + list_display = [ + 'id', 'enable', + 'user', 'subscribe', 'subscribe_for_user', + 'sum', 'currency', + 'status', 'last_operation_status', + 'order', 'modifiedDT', 'createDT' + ] + + list_display_links = ['id', 'user', 'subscribe'] + list_editable = ['enable'] + + readonly_fields = ['subscribe_for_user', 'sum', 'currency', 'modifiedDT', 'createDT'] + + list_filter = ['enable', 'status', 'modifiedDT', 'createDT'] + search_fields = ['id', 'last_operation_status', 'status'] + # filter_horizontal = ['options'] + +admin.site.register(SubscribeOrder, Admin_SubscribeOrder) \ No newline at end of file diff --git a/BillingApp/apps.py b/BillingApp/apps.py new file mode 100644 index 0000000..a42d49d --- /dev/null +++ b/BillingApp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BillingappConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'BillingApp' diff --git a/BillingApp/funcs.py b/BillingApp/funcs.py new file mode 100644 index 0000000..6da202a --- /dev/null +++ b/BillingApp/funcs.py @@ -0,0 +1,88 @@ +from datetime import datetime + +from .models import * +import json + + +def get_order_status(order): + from BaseModels.pay_systems.DVL_Group_kaz.api.funcs import get_order_status + res_status = None + + try: + res_data = get_order_status(order.bank_order_id) + + res = json.loads(res_data.text) + order.json_data['status'] = res + res = res['orders'][0] + + order.status = res['status'] + + + # if res['amount'] == res['amount_charged'] and res['status'] == 'charged': + order.save() + return order.status + + + except Exception as e: + msg = f'Exception get_order_status = {str(e)}' + if order: + msg = f'Exception get_order_status (data = {str(order.id)}) = {str(e)}' + print(msg) + + return None + +def get_orders_for_user(user): + + orders = SubscribeOrder.objects.filter( + enable=True, + user=user, + subscribe_for_user=None + ).order_by('-modifiedDT') + return orders + + +def create_subscribe_order(data): + order = None + + try: + + order = SubscribeOrder.objects.create(**data) + + from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options + sets = get_options_by_opt_types(['domain', 'project_name'], only_vals=True) + + from BaseModels.pay_systems.DVL_Group_kaz.api.funcs import create_order + data = { + 'currency': data['currency'], + 'amount': data['sum'], + 'description': f'Заказ {order.id} на подписку ' + f'{data["subscribe"].name} ' + f'для пользователя {data["user"].username}', + 'options': { + 'auto_charge': 1, + 'return_url': f'{sets["domain"]}/profile/page/my_subscribe/' + } + } + + res_data = create_order(data) + + order.pay_page = res_data.headers.get('location') + + res = json.loads(res_data.text) + order.json_data['create_order'] = res + res = res['orders'][0] + order.modifiedDT = datetime.strptime(res['updated'], '%Y-%m-%d %H:%M:%S') + order.status = res['status'] + order.bank_order_id = res['id'] + if 'segment' in res: + order.segment = res['segment'] + if 'merchant_order_id' in res: + order.merchant_order_id = res['merchant_order_id'] + order.save() + + + except Exception as e: + msg = f'Exception create_subscribe_order (data = {str(data)}) = {str(e)}' + print(msg) + + return order \ No newline at end of file diff --git a/BillingApp/migrations/__init__.py b/BillingApp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/BillingApp/models.py b/BillingApp/models.py new file mode 100644 index 0000000..1c2e8fb --- /dev/null +++ b/BillingApp/models.py @@ -0,0 +1,51 @@ +from django.db import models +from BaseModels.base_models import BaseModel +from SubscribesApp.models import Subscribe, SubscribeForUser +from AuthApp.models import User +from django.utils.translation import gettext as _ + +class SubscribeOrder(BaseModel): + + subscribe = models.ForeignKey( + Subscribe, verbose_name=_('Подписка'), + on_delete=models.SET_NULL, blank=True, null=True, + related_name='subscribe_orders_for_subscribe' + ) + + user = models.ForeignKey( + User, verbose_name=_('Пользователь'), + on_delete=models.SET_NULL, blank=True, null=True, + related_name='subscribe_orders_for_user' + ) + + subscribe_for_user = models.OneToOneField( + SubscribeForUser, verbose_name=_('Подписка пользователя'), + on_delete=models.SET_NULL, blank=True, null=True, + related_name='subscribe_orders_for_user_subscribe' + ) + + sum = models.PositiveSmallIntegerField(verbose_name=_('Сумма'), default=0) + currency = models.CharField(verbose_name=_('Валюта'), max_length=3, default='USD') + segment = models.CharField(verbose_name=_('ID Сегмента'), null=True, default=None) + merchant_order_id = models.CharField(verbose_name=_('merchant_order_id'), null=True, default=None) + bank_order_id = models.CharField(verbose_name=_('ID заказа в банке'), null=True, default=None) + + status = models.CharField(verbose_name=_('Статус заказа в банке'), null=True, default=None) + last_operation_status = models.CharField(verbose_name=_('Статус последней операции'), null=True, default=None) + + pay_page = models.URLField(verbose_name=_('Ссылка на страницу оплаты'), null=True, blank=True, default=None) + + class Meta: + verbose_name = _('Заказ на подписку') + verbose_name_plural = _('Заказы на подписки') + + def __str__(self): + res = 'Заказ' + if self.subscribe: + res += f' на подписку {self.subscribe.name}' + if self.user: + res += f' для {self.user.username}' + + if not res: + res += f' {str(self.id)}' + return res \ No newline at end of file diff --git a/BillingApp/tests.py b/BillingApp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/BillingApp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/BillingApp/views.py b/BillingApp/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/BillingApp/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/GeneralApp/views.py b/GeneralApp/views.py index dae385f..c0f2015 100644 --- a/GeneralApp/views.py +++ b/GeneralApp/views.py @@ -24,8 +24,11 @@ def test_code(request): # apps = SocialApp.objects.all() # apps.delete() - from PushMessages.views import send_push - send_push(request.user, 'test_title', 'test_content') + # from PushMessages.views import send_push + # send_push(request.user, 'test_title', 'test_content') + + from BaseModels.pay_systems.DVL_Group_kaz.api.funcs import create_order + create_order() # from RoutesApp.search_matches import search_matches # search_matches() diff --git a/SubscribesApp/funcs.py b/SubscribesApp/funcs.py index 20e0aac..aa542c8 100644 --- a/SubscribesApp/funcs.py +++ b/SubscribesApp/funcs.py @@ -1,6 +1,7 @@ from .models import * from django.template.loader import render_to_string from django.utils.translation import get_language, activate +from datetime import datetime, timedelta def get_cur_user_subscribe(user): @@ -13,7 +14,7 @@ def get_cur_user_subscribe(user): return user_subscribe -def get_subsribes_w_options(): +def get_subscribes_w_options(): all_options = SubscribeOption.objects.filter(enable=True) subscribes = Subscribe.objects.filter(enable=True) for subscribe in subscribes: @@ -23,6 +24,28 @@ def get_subsribes_w_options(): return subscribes, all_options +def check_n_enable_subscribe_by_order(order): + + subscribes_for_user = SubscribeForUser.objects.filter(user=order.user) + + if order and order.enable and order.status == 'charged': + kwargs = { + 'user': order.user, + 'subscribe': order.subscribe, + 'last_paid_DT': datetime.now(), + 'paid_period_from_DT': datetime.now(), + 'paid_period_to_DT': datetime.now() + timedelta(hours=order.subscribe.period), + 'receive_finish_subscribe_msg': True, + } + subscribe_for_user = SubscribeForUser.objects.create(**kwargs) + order.subscribe_for_user = subscribe_for_user + order.save() + + subscribes_for_user = [subscribe_for_user] + + return subscribes_for_user + + def get_profile_subscribe_page_content_html(request): try: @@ -32,9 +55,20 @@ def get_profile_subscribe_page_content_html(request): # data = json.loads(request.body) # all_options = SubscribeOption.objects.filter(enable=True) - subscribes, all_options = get_subsribes_w_options() + subscribes, all_options = get_subscribes_w_options() + + subscribe_for_user = None + + if request.user and request.user.is_authenticated: + from BillingApp.funcs import get_orders_for_user, get_order_status + orders = get_orders_for_user(request.user) + for order in orders: + res = get_order_status(order) + subscribe_for_user = check_n_enable_subscribe_by_order(order) + + if not subscribe_for_user: + subscribe_for_user = SubscribeForUser.objects.filter(user=request.user) - subscribe_for_user = SubscribeForUser.objects.filter(user=request.user) if not subscribe_for_user: tpl_name = 'blocks/profile/b_subscribe_variants.html' else: diff --git a/SubscribesApp/js_views.py b/SubscribesApp/js_views.py index be6ee84..b89c6b3 100644 --- a/SubscribesApp/js_views.py +++ b/SubscribesApp/js_views.py @@ -3,7 +3,7 @@ from django.shortcuts import render from uuid import uuid1 from .models import * from django.contrib import auth -from django.http import HttpResponse, Http404, JsonResponse +from django.http import HttpResponse, Http404, JsonResponse, HttpResponseRedirect from django.template import loader, RequestContext from django.contrib.auth.decorators import login_required from BaseModels.mailSender import techSendMail @@ -17,6 +17,7 @@ from datetime import datetime, time, timedelta from channels.layers import get_channel_layer from asgiref.sync import async_to_sync from GeneralApp.funcs import get_and_set_lang +from django.shortcuts import redirect @login_required()#login_url='/profile/login/') @@ -33,6 +34,18 @@ def subscribe_now_ajax(request): subscribe = Subscribe.objects.get(id=data['subscribe_id']) + kwargs_for_order = { + 'user': request.user, + 'subscribe': subscribe, + 'currency': 'USD', + 'sum': subscribe.price, + } + + from BillingApp.funcs import create_subscribe_order + order = create_subscribe_order(kwargs_for_order) + if order: + return JsonResponse({'redirect': order.pay_page}) + kwargs = { 'user': request.user, 'subscribe': subscribe, @@ -41,13 +54,10 @@ def subscribe_now_ajax(request): 'paid_period_to_DT': datetime.now() + timedelta(hours=subscribe.period), 'receive_finish_subscribe_msg': True, } - subscribe_for_user = SubscribeForUser.objects.filter(user=request.user) if subscribe_for_user: subscribe_for_user.update(**kwargs) subscribe_for_user = subscribe_for_user[0] - else: - subscribe_for_user = SubscribeForUser.objects.create(**kwargs) if not subscribe_for_user: tpl_name = 'blocks/profile/b_subscribe_variants.html' diff --git a/SubscribesApp/models.py b/SubscribesApp/models.py index 60a822f..6b0ffd4 100644 --- a/SubscribesApp/models.py +++ b/SubscribesApp/models.py @@ -49,4 +49,15 @@ class SubscribeForUser(BaseModel): class Meta: verbose_name = _('Пользовательская подписка') - verbose_name_plural = _('Пользовательские подписки') \ No newline at end of file + verbose_name_plural = _('Пользовательские подписки') + + def __str__(self): + res = 'Подписка' + if self.subscribe: + res += f' {self.subscribe.name}' + if self.user: + res += f' для {self.user.username}' + + if not res: + res += f' {str(self.id)}' + return res \ No newline at end of file diff --git a/TWB/settings.py b/TWB/settings.py index 5cfa9f2..dbe2f84 100644 --- a/TWB/settings.py +++ b/TWB/settings.py @@ -118,6 +118,7 @@ INSTALLED_APPS = [ 'ArticlesApp', 'SubscribesApp', 'PushMessages', + 'BillingApp', ] MIDDLEWARE = [ diff --git a/dvldigitalprojects.p12 b/dvldigitalprojects.p12 new file mode 100644 index 0000000..47964d7 Binary files /dev/null and b/dvldigitalprojects.p12 differ diff --git a/requirements.pip b/requirements.pip index 80e15ca..3bbd488 100644 --- a/requirements.pip +++ b/requirements.pip @@ -13,5 +13,6 @@ django-colorfield django-webpush==0.3.5 django-allauth==0.60.0 pytz==2024.1 +requests-pkcs12==1.24 #django-tz-detect==0.4.0