@@ -89,19 +89,4 @@ PATH_PREFETCH_MAP = { ), ), }, - '/api/v1/v2/payments/plans': { - 'select': ( - 'host_account', - 'payment_plan', - 'business_account__parent_company__user__payment_plan__plan', - 'payment_plan__plan', - 'payment_plan__method', - ), - 'prefetch': ( - Prefetch( - 'business_account__parent_company__user__payment_plan__plan', - queryset=NeuronModel.objects.only('slug'), - ), - ), - }, } @@ -18,7 +18,6 @@ from backend.public import urlpatterns as public_urlpatterns api = NinjaAPI(title='AIR API', version='1.0.0', docs_url=None) compatibility_api = NinjaAPI(title='AIR API DEBUG', version='0.0.1', docs_url=None) -compatibility_api_v2 = NinjaAPI(title='AIR API DEBUG', version='0.0.2', docs_url=None) api.add_router('copywrite/', 'tools.copywrite.routes.v1.router') api.add_router('users/', 'users.routes.v1.router') @@ -30,9 +29,6 @@ compatibility_api.add_router('payments/', 'payments.routes.v1.router') compatibility_api.add_router('reports/', 'reports.routes.v1.router') compatibility_api.add_router('ml_model/', 'ml_model.routes.v1.router') -compatibility_api_v2.add_router('payments/', 'payments.routes.v2.router') - - logger = logging.getLogger(__name__) @@ -67,7 +63,6 @@ urlpatterns += [ urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) api.docs_url = '/docs' compatibility_api.docs_url = '/docs' -compatibility_api_v2.docs_url = '/docs' urlpatterns += [ path('api/v1/healthz/', healthz_status), @@ -90,7 +85,6 @@ urlpatterns += [ ), path('api/v1/api/', api.urls), path('api/v1/', compatibility_api.urls), - path('api/v1/v2/', compatibility_api_v2.urls), ] urlpatterns += public_urlpatterns @@ -230,7 +230,7 @@ async def create_payment_link(request, body: NewSubscriptionSchema): if request.auth.account_type not in {'regular', 'business_host'}: raise HttpError(401, 'Unauthorized') payment_plan = await PaymentPlan.objects.aget(uid=body.uid) - payment_url = (await PaymentService(request.auth).create_payment_link(payment_plan))[0] + payment_url = await PaymentService(request.auth).create_payment_link(payment_plan) logger.info( 'Payment link endpoint completed: email=%s plan_uid=%s', request.auth.email, @@ -1,33 +0,0 @@ -import logging - -from ninja import Router -from ninja.errors import HttpError - -from authentication.security import AsyncAuthBearer, SyncAuthBearer - -from payments.models import PaymentPlan -from payments.schemas import NewSubscriptionSchema, PaymentLinkPriceSchema -from payments.services.payment_service import PaymentService - -router = Router(auth=SyncAuthBearer(), tags=['payments']) - -logger = logging.getLogger(__name__) - - -@router.post('plans', tags=['payments/plans'], auth=AsyncAuthBearer(), response=PaymentLinkPriceSchema) -async def create_payment_link(request, body: NewSubscriptionSchema): - try: - if request.auth.account_type not in {'regular', 'business_host'}: - raise HttpError(401, 'Unauthorized') - payment_plan = await PaymentPlan.objects.aget(uid=body.uid) - payment_url, plan_price, plan_tokens = await PaymentService(request.auth).create_payment_link( - payment_plan - ) - logger.info( - 'Payment link endpoint completed: email=%s plan_uid=%s', - request.auth.email, - payment_plan.uid, - ) - return PaymentLinkPriceSchema(payment_url=payment_url, price=plan_price, buying_tokens=plan_tokens) - except Exception as exc: - raise HttpError(400, f'{exc}') \ No newline at end of file @@ -30,38 +30,13 @@ class PaymentService: def __init__(self, user: CustomUserModel): self.user = user - async def create_payment_link(self, plan: PaymentPlan) -> tuple[str, Decimal, Decimal]: - current_plan = self.user.payment_plan.plan - current_balance = self.user.payment_plan.current_token_balance - plan_price = plan.price - plan_tokens = plan.tokens_per_plan - if ( - current_balance >= plan_tokens - and plan == current_plan - and web_client.get_flag_state('recurring_payments', self.user.email) - ): - raise FullBalanceException - if 0 < current_plan.price <= plan.price and self.user.payment_plan.is_recurring: - plans_price_diff = plan.price - current_plan.price - token_price = current_plan.price / current_plan.tokens_per_plan - tokens_diff = current_plan.tokens_per_plan - current_balance - additional_tokens = 0 if tokens_diff < 0 else tokens_diff - plan_price = Decimal(plans_price_diff + (token_price * additional_tokens)).quantize( - Decimal('1'), rounding='ROUND_UP' - ) - balance_sufficient = (plan_tokens - current_balance) <= 0 - plan_tokens = ( - plan_tokens - current_plan.tokens_per_plan - if balance_sufficient - else (plan_tokens - current_balance) - ) - product_title = f'Вы {"купили план" if current_plan.price != plan.price else "восстановили баланс по плану"} {plan.tokens_per_plan} токенов' + async def create_payment_link(self, plan: PaymentPlan) -> str: receipt_data = { 'customer': {'email': self.user.email}, 'items': [ { - 'description': product_title, - 'amount': {'value': f'{plan_price}', 'currency': 'RUB'}, + 'description': 'План в AIR', + 'amount': {'value': f'{plan.price}', 'currency': 'RUB'}, 'vat_code': 1, 'quantity': '1', } @@ -71,7 +46,7 @@ class PaymentService: web_client.get_flag_state('recurring_payments', self.user.email) and not plan.individual ) payment_data = { - 'amount': {'value': f'{plan_price}', 'currency': 'RUB'}, + 'amount': {'value': f'{plan.price}', 'currency': 'RUB'}, 'payment_method_data': {'type': 'bank_card'}, 'receipt': receipt_data, 'confirmation': { @@ -81,24 +56,17 @@ class PaymentService: 'description': str(self.user.uid), 'capture': True, 'save_payment_method': is_recurring, - 'metadata': { - 'plan_uid': str(plan.uid), - 'buying_tokens': str(plan_tokens), - }, + 'metadata': {'plan_uid': str(plan.uid)}, } payment = YookassaPayment.create(payment_data, uuid4()) logger.info( 'Payment link created: email=%s plan_uid=%s price=%s recurring=%s', self.user.email, plan.uid, - plan_price, + plan.price, is_recurring, ) - return ( - payment.confirmation.confirmation_url, - plan_price, - plan_tokens.quantize(Decimal('1'), rounding='ROUND_UP'), - ) + return payment.confirmation.confirmation_url @sync_to_async def do_payment(self, payment: YookassaPaymentResponse) -> PaymentModel: @@ -115,8 +83,10 @@ class PaymentService: if payment.status == 'waiting_for_capture': self.handle_captured_payment(payment.id) elif payment.status == 'succeeded': - buying_tokens = self.calculate_buying_tokens( - Decimal(f'{payment.metadata["buying_tokens"]}'), payment_instance.plan + buying_tokens = ( + payment_instance.plan.tokens_per_plan + if payment.metadata.get('recurring') + else self.calculate_buying_tokens(payment_instance.plan) ) self.handle_succeeded_payment(payment, payment_instance.plan) PaymentPlanService(self.user).subscribe_user_to_plan(payment_instance.plan, buying_tokens) @@ -135,19 +105,10 @@ class PaymentService: YookassaPayment.capture(str(payment_id)) logger.info('Payment captured: payment_id=%s email=%s', payment_id, self.user.email) - def calculate_buying_tokens(self, buying_tokens: Decimal, plan: PaymentPlan): - if not web_client.get_flag_state('recurring_payments', self.user.email): - return self.user.payment_plan.current_token_balance + buying_tokens - current_plan_price = self.user.payment_plan.plan.price - cap = plan.tokens_per_plan - if current_plan_price == Decimal('0') or current_plan_price > plan.price: - return min(buying_tokens, cap) - if self.user.payment_plan.is_recurring: - current_balance = self.user.payment_plan.current_token_balance - if current_balance >= cap: - return cap - return min(current_balance + buying_tokens, cap) - return min(buying_tokens, cap) + def calculate_buying_tokens(self, plan: PaymentPlan): + if self.user.payment_plan.plan.price == Decimal('0'): + return plan.tokens_per_plan + return self.user.payment_plan.current_token_balance + plan.tokens_per_plan def handle_succeeded_payment(self, payment: YookassaPaymentResponse, plan: PaymentPlan) -> None: if ( @@ -1,5 +1,4 @@ from datetime import date, datetime -from decimal import Decimal from typing import List, Optional from uuid import UUID @@ -80,6 +79,3 @@ class ExpensesSchema(Schema): amount: condecimal(max_digits=10, decimal_places=2) -class PaymentLinkPriceSchema(PaymentLinkSchema): - price: Decimal - buying_tokens: Decimal @@ -92,7 +92,6 @@ def execute_recurring_payments() -> None: 'metadata': { 'recurring': True, 'plan_uid': str(plan.uid), - 'buying_tokens': str(plan.tokens_per_plan), }, } YookassaPayment.create(payment_data, uuid4())