fix: добавить create_transaction для 6 потоков оплаты с баланса
- trial_activation_service: create_transaction после списания за триал - purchase.py: create_transaction для платного триала через бот - cabinet/subscription.py: create_transaction для продления и триала, исправлены transaction=None → реальный объект в 5 уведомлениях - simple_subscription.py: create_transaction в обоих обработчиках, transaction передаётся в admin-уведомление вместо None
This commit is contained in:
@@ -21,7 +21,7 @@ from app.database.crud.subscription import (
|
||||
from app.database.crud.tariff import get_tariff_by_id, get_tariffs_for_user
|
||||
from app.database.crud.transaction import create_transaction
|
||||
from app.database.crud.user import subtract_user_balance
|
||||
from app.database.models import ServerSquad, Subscription, Tariff, TransactionType, User
|
||||
from app.database.models import PaymentMethod, ServerSquad, Subscription, Tariff, TransactionType, User
|
||||
from app.services.notification_delivery_service import (
|
||||
NotificationType,
|
||||
notification_delivery_service,
|
||||
@@ -537,11 +537,12 @@ async def renew_subscription(
|
||||
# Deduct balance (centralized: row-level lock, promo consumption, paid subscription flag)
|
||||
from app.database.crud.user import subtract_user_balance
|
||||
|
||||
renewal_description = f'Продление подписки на {request.period_days} дней' + (f' ({tariff.name})' if tariff else '')
|
||||
success = await subtract_user_balance(
|
||||
db,
|
||||
user,
|
||||
price_kopeks,
|
||||
f'Продление подписки на {request.period_days} дней' + (f' ({tariff.name})' if tariff else ''),
|
||||
renewal_description,
|
||||
consume_promo_offer=promo_offer_discount_value > 0,
|
||||
mark_as_paid_subscription=True,
|
||||
)
|
||||
@@ -554,6 +555,16 @@ async def renew_subscription(
|
||||
},
|
||||
)
|
||||
|
||||
# Создаём транзакцию для учёта списания
|
||||
transaction = await create_transaction(
|
||||
db,
|
||||
user_id=user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=price_kopeks,
|
||||
description=renewal_description,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
|
||||
await db.refresh(user, ['subscription'])
|
||||
|
||||
# Extend from end_date or now if expired
|
||||
@@ -628,7 +639,7 @@ async def renew_subscription(
|
||||
db=db,
|
||||
user=user,
|
||||
subscription=user.subscription,
|
||||
transaction=None,
|
||||
transaction=transaction,
|
||||
period_days=request.period_days,
|
||||
was_trial_conversion=False,
|
||||
amount_kopeks=price_kopeks,
|
||||
@@ -1339,11 +1350,12 @@ async def activate_trial(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f'Insufficient balance. Need {price_kopeks / 100:.2f} RUB',
|
||||
)
|
||||
trial_description = 'Активация триальной подписки'
|
||||
success = await subtract_user_balance(
|
||||
db,
|
||||
user,
|
||||
price_kopeks,
|
||||
'Активация триальной подписки',
|
||||
trial_description,
|
||||
mark_as_paid_subscription=True,
|
||||
)
|
||||
if not success:
|
||||
@@ -1351,6 +1363,17 @@ async def activate_trial(
|
||||
status_code=status.HTTP_402_PAYMENT_REQUIRED,
|
||||
detail='Failed to charge trial activation fee',
|
||||
)
|
||||
|
||||
# Создаём транзакцию для учёта списания за триал
|
||||
await create_transaction(
|
||||
db,
|
||||
user_id=user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=price_kopeks,
|
||||
description=trial_description,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
|
||||
logger.info('User paid kopeks for trial activation', user_id=user.id, price_kopeks=price_kopeks)
|
||||
|
||||
# Get trial parameters from tariff if configured (same logic as bot handler)
|
||||
@@ -1830,7 +1853,7 @@ async def submit_purchase(
|
||||
db=db,
|
||||
user=user,
|
||||
subscription=subscription,
|
||||
transaction=None,
|
||||
transaction=result.get('transaction'),
|
||||
period_days=selection.period.days,
|
||||
was_trial_conversion=result.get('was_trial_conversion', False),
|
||||
amount_kopeks=pricing.final_total,
|
||||
@@ -2130,12 +2153,13 @@ async def purchase_tariff(
|
||||
)
|
||||
|
||||
# Create transaction
|
||||
await create_transaction(
|
||||
transaction = await create_transaction(
|
||||
db=db,
|
||||
user_id=user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=price_kopeks,
|
||||
description=description,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
|
||||
if subscription:
|
||||
@@ -2283,7 +2307,7 @@ async def purchase_tariff(
|
||||
db=db,
|
||||
user=user,
|
||||
subscription=subscription,
|
||||
transaction=None,
|
||||
transaction=transaction,
|
||||
period_days=period_days,
|
||||
was_trial_conversion=False,
|
||||
amount_kopeks=price_kopeks,
|
||||
@@ -4268,12 +4292,13 @@ async def switch_tariff(
|
||||
)
|
||||
|
||||
# Create transaction
|
||||
await create_transaction(
|
||||
switch_transaction = await create_transaction(
|
||||
db=db,
|
||||
user_id=user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=upgrade_cost,
|
||||
description=description,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
|
||||
# Update subscription
|
||||
@@ -4357,7 +4382,7 @@ async def switch_tariff(
|
||||
db=db,
|
||||
user=user,
|
||||
subscription=user.subscription,
|
||||
transaction=None,
|
||||
transaction=switch_transaction if upgrade_cost > 0 else None,
|
||||
period_days=remaining_days if remaining_days > 0 else new_period_days,
|
||||
was_trial_conversion=False,
|
||||
amount_kopeks=upgrade_cost,
|
||||
|
||||
@@ -433,11 +433,12 @@ async def handle_simple_subscription_pay_with_balance(
|
||||
# Списываем средства с баланса пользователя
|
||||
from app.database.crud.user import subtract_user_balance
|
||||
|
||||
purchase_description = f'Оплата подписки на {subscription_params["period_days"]} дней'
|
||||
success = await subtract_user_balance(
|
||||
db,
|
||||
db_user,
|
||||
price_kopeks,
|
||||
f'Оплата подписки на {subscription_params["period_days"]} дней',
|
||||
purchase_description,
|
||||
consume_promo_offer=False,
|
||||
mark_as_paid_subscription=True,
|
||||
)
|
||||
@@ -446,6 +447,19 @@ async def handle_simple_subscription_pay_with_balance(
|
||||
await callback.answer('❌ Ошибка списания средств с баланса', show_alert=True)
|
||||
return
|
||||
|
||||
# Создаём транзакцию для учёта списания
|
||||
from app.database.crud.transaction import create_transaction
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
|
||||
transaction = await create_transaction(
|
||||
db,
|
||||
user_id=db_user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=price_kopeks,
|
||||
description=purchase_description,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
|
||||
# Проверяем, есть ли у пользователя уже подписка
|
||||
from app.database.crud.subscription import extend_subscription, get_subscription_by_user_id
|
||||
|
||||
@@ -631,7 +645,7 @@ async def handle_simple_subscription_pay_with_balance(
|
||||
db,
|
||||
db_user,
|
||||
subscription,
|
||||
None, # transaction
|
||||
transaction,
|
||||
subscription_params['period_days'],
|
||||
False, # was_trial_conversion
|
||||
amount_kopeks=price_kopeks,
|
||||
@@ -2138,11 +2152,12 @@ async def confirm_simple_subscription_purchase(
|
||||
# Списываем средства с баланса пользователя
|
||||
from app.database.crud.user import subtract_user_balance
|
||||
|
||||
purchase_description = f'Оплата подписки на {subscription_params["period_days"]} дней'
|
||||
success = await subtract_user_balance(
|
||||
db,
|
||||
db_user,
|
||||
price_kopeks,
|
||||
f'Оплата подписки на {subscription_params["period_days"]} дней',
|
||||
purchase_description,
|
||||
consume_promo_offer=False,
|
||||
mark_as_paid_subscription=True,
|
||||
)
|
||||
@@ -2151,6 +2166,19 @@ async def confirm_simple_subscription_purchase(
|
||||
await callback.answer('❌ Ошибка списания средств с баланса', show_alert=True)
|
||||
return
|
||||
|
||||
# Создаём транзакцию для учёта списания
|
||||
from app.database.crud.transaction import create_transaction
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
|
||||
transaction = await create_transaction(
|
||||
db,
|
||||
user_id=db_user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=price_kopeks,
|
||||
description=purchase_description,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
|
||||
# Проверяем, есть ли у пользователя уже подписка
|
||||
from app.database.crud.subscription import extend_subscription, get_subscription_by_user_id
|
||||
|
||||
@@ -2336,7 +2364,7 @@ async def confirm_simple_subscription_purchase(
|
||||
db,
|
||||
db_user,
|
||||
subscription,
|
||||
None, # transaction
|
||||
transaction,
|
||||
subscription_params['period_days'],
|
||||
False, # was_trial_conversion
|
||||
amount_kopeks=price_kopeks,
|
||||
|
||||
@@ -16,7 +16,7 @@ from app.database.crud.subscription import (
|
||||
)
|
||||
from app.database.crud.transaction import create_transaction
|
||||
from app.database.crud.user import subtract_user_balance
|
||||
from app.database.models import Subscription, SubscriptionStatus, TransactionType, User
|
||||
from app.database.models import PaymentMethod, Subscription, SubscriptionStatus, TransactionType, User
|
||||
from app.keyboards.inline import (
|
||||
get_back_keyboard,
|
||||
get_countries_keyboard,
|
||||
@@ -3301,6 +3301,17 @@ async def handle_trial_pay_with_balance(callback: types.CallbackQuery, db_user:
|
||||
await callback.answer(texts.t('PAYMENT_FAILED', '❌ Не удалось списать средства'), show_alert=True)
|
||||
return
|
||||
|
||||
# Создаём транзакцию для учёта списания за триал
|
||||
trial_description = texts.t('TRIAL_PAYMENT_DESCRIPTION', 'Оплата пробной подписки')
|
||||
await create_transaction(
|
||||
db,
|
||||
user_id=db_user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=trial_price_kopeks,
|
||||
description=trial_description,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
|
||||
await db.refresh(db_user)
|
||||
|
||||
# Сохраняем ID до начала транзакции (на случай detached session)
|
||||
|
||||
@@ -7,8 +7,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import settings
|
||||
from app.database.crud.subscription import decrement_subscription_server_counts
|
||||
from app.database.crud.transaction import create_transaction
|
||||
from app.database.crud.user import add_user_balance, subtract_user_balance
|
||||
from app.database.models import Subscription, TransactionType, User
|
||||
from app.database.models import PaymentMethod, Subscription, TransactionType, User
|
||||
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
@@ -94,7 +95,16 @@ async def charge_trial_activation_if_required(
|
||||
if not success:
|
||||
raise TrialPaymentChargeFailed
|
||||
|
||||
# subtract_user_balance обновляет пользователя, но на всякий случай приводим к int
|
||||
# Создаём транзакцию для учёта списания за триал
|
||||
await create_transaction(
|
||||
db,
|
||||
user_id=user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=price_kopeks,
|
||||
description=charge_description,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
|
||||
return int(price_kopeks)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user