fix(payments): Исправлена ошибка с дублированием скидки для всех платёжных систем

This commit is contained in:
VAQYBIN
2026-01-23 00:00:16 +05:00
parent 1e8b97888a
commit a121d38fbb
7 changed files with 165 additions and 37 deletions
@@ -10,7 +10,6 @@ from bot.middlewares.i18n import JsonI18n
from bot.services.freekassa_service import FreeKassaService
from config.settings import Settings
from db.dal import payment_dal
from bot.handlers.user.subscription.payment_discount_helper import apply_discount_to_payment
router = Router(name="user_subscription_payments_freekassa_router")
@@ -70,22 +69,19 @@ async def pay_fk_callback_handler(
)
currency_code = getattr(freekassa_service, "default_currency", None) or settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
# Apply active discount if exists
final_price_rub, discount_amount, promo_code_id = await apply_discount_to_payment(
session, user_id, price_rub, promo_code_service
)
# Price is already discounted at payments_subscription.py stage
# Service will handle discount metadata if needed
payment_record_payload = {
"user_id": user_id,
"amount": final_price_rub,
"original_amount": price_rub if discount_amount else None,
"discount_applied": discount_amount,
"amount": price_rub,
"original_amount": None,
"discount_applied": None,
"currency": currency_code,
"status": "pending_freekassa",
"description": payment_description,
"subscription_duration_months": int(months),
"provider": "freekassa",
"promo_code_id": promo_code_id,
"promo_code_id": None,
}
try:
@@ -111,13 +107,15 @@ async def pay_fk_callback_handler(
payment_db_id=payment_record.payment_id,
user_id=payment_record.user_id,
months=months,
amount=final_price_rub,
amount=price_rub,
currency=freekassa_service.default_currency,
payment_method_id=freekassa_service.payment_method_id,
ip_address=freekassa_service.server_ip,
extra_params={
"us_method": freekassa_service.payment_method_id,
},
promo_code_service=promo_code_service,
session=session,
)
if success:
@@ -10,7 +10,6 @@ from bot.middlewares.i18n import JsonI18n
from bot.services.platega_service import PlategaService
from config.settings import Settings
from db.dal import payment_dal
from bot.handlers.user.subscription.payment_discount_helper import apply_discount_to_payment
router = Router(name="user_subscription_payments_platega_router")
@@ -70,22 +69,19 @@ async def pay_platega_callback_handler(
)
currency_code = settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
# Apply active discount if exists
final_price_rub, discount_amount, promo_code_id = await apply_discount_to_payment(
session, user_id, price_rub, promo_code_service
)
# Price is already discounted at payments_subscription.py stage
# Service will handle discount metadata if needed
payment_record_payload = {
"user_id": user_id,
"amount": final_price_rub,
"original_amount": price_rub if discount_amount else None,
"discount_applied": discount_amount,
"amount": price_rub,
"original_amount": None,
"discount_applied": None,
"currency": currency_code,
"status": "pending_platega",
"description": payment_description,
"subscription_duration_months": int(months),
"provider": "platega",
"promo_code_id": promo_code_id,
"promo_code_id": None,
}
try:
@@ -120,10 +116,12 @@ async def pay_platega_callback_handler(
payment_db_id=payment_record.payment_id,
user_id=user_id,
months=months,
amount=final_price_rub,
amount=price_rub,
currency=currency_code,
description=payment_description,
payload=payload_meta,
promo_code_service=promo_code_service,
session=session,
)
if success:
@@ -9,7 +9,6 @@ from bot.middlewares.i18n import JsonI18n
from bot.services.severpay_service import SeverPayService
from config.settings import Settings
from db.dal import payment_dal
from bot.handlers.user.subscription.payment_discount_helper import apply_discount_to_payment
router = Router(name="user_subscription_payments_severpay_router")
@@ -69,22 +68,19 @@ async def pay_severpay_callback_handler(
)
currency_code = settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
# Apply active discount if exists
final_price_rub, discount_amount, promo_code_id = await apply_discount_to_payment(
session, user_id, price_rub, promo_code_service
)
# Price is already discounted at payments_subscription.py stage
# Service will handle discount metadata if needed
payment_record_payload = {
"user_id": user_id,
"amount": final_price_rub,
"original_amount": price_rub if discount_amount else None,
"discount_applied": discount_amount,
"amount": price_rub,
"original_amount": None,
"discount_applied": None,
"currency": currency_code,
"status": "pending_severpay",
"description": payment_description,
"subscription_duration_months": int(months),
"provider": "severpay",
"promo_code_id": promo_code_id,
"promo_code_id": None,
}
try:
@@ -110,9 +106,11 @@ async def pay_severpay_callback_handler(
payment_db_id=payment_record.payment_id,
user_id=user_id,
months=months,
amount=final_price_rub,
amount=price_rub,
currency=currency_code,
description=payment_description,
promo_code_service=promo_code_service,
session=session,
)
if success:
+36
View File
@@ -78,11 +78,47 @@ class FreeKassaService:
ip_address: Optional[str] = None,
payment_method_id: Optional[int] = None,
extra_params: Optional[Dict[str, Any]] = None,
promo_code_service=None,
session=None,
) -> Tuple[bool, Dict[str, Any]]:
if not self.configured:
logging.error("FreeKassaService is not configured. Cannot create order.")
return False, {"message": "service_not_configured"}
# Check for active discount to save metadata (price already discounted from previous step)
original_amount = None
discount_amount = None
promo_code_id = None
if promo_code_service and session:
from db.dal import active_discount_dal
active_discount = await active_discount_dal.get_active_discount(session, user_id)
if active_discount:
# Price is already discounted, calculate original price backwards
discount_pct = active_discount.discount_percentage
original_amount = amount / (1 - discount_pct / 100)
discount_amount = original_amount - amount
promo_code_id = active_discount.promo_code_id
logging.info(
f"Recording {discount_pct}% discount for FreeKassa payment: "
f"original {original_amount:.2f} -> final {amount}"
)
# Update payment record with discount metadata
try:
await payment_dal.update_payment_discount_info(
session,
payment_db_id,
original_amount,
discount_amount,
promo_code_id,
)
await session.commit()
except Exception as e_update:
logging.warning(
f"FreeKassa: failed to update discount metadata for payment {payment_db_id}: {e_update}"
)
ip_address = ip_address or self.server_ip
if not ip_address:
logging.error("FreeKassaService: payment IP is required but not configured.")
+38 -2
View File
@@ -76,12 +76,48 @@ class PlategaService:
currency: Optional[str],
description: str,
payload: Optional[str] = None,
promo_code_service=None,
session=None,
) -> Tuple[bool, Dict[str, Any]]:
if not self.configured:
logging.error("PlategaService is not configured. Cannot create transaction.")
return False, {"message": "service_not_configured"}
session = await self._get_session()
# Check for active discount to save metadata (price already discounted from previous step)
original_amount = None
discount_amount = None
promo_code_id = None
if promo_code_service and session:
from db.dal import active_discount_dal
active_discount = await active_discount_dal.get_active_discount(session, user_id)
if active_discount:
# Price is already discounted, calculate original price backwards
discount_pct = active_discount.discount_percentage
original_amount = amount / (1 - discount_pct / 100)
discount_amount = original_amount - amount
promo_code_id = active_discount.promo_code_id
logging.info(
f"Recording {discount_pct}% discount for Platega payment: "
f"original {original_amount:.2f} -> final {amount}"
)
# Update payment record with discount metadata
try:
await payment_dal.update_payment_discount_info(
session,
payment_db_id,
original_amount,
discount_amount,
promo_code_id,
)
await session.commit()
except Exception as e_update:
logging.warning(
f"Platega: failed to update discount metadata for payment {payment_db_id}: {e_update}"
)
http_session = await self._get_session()
url = f"{self.base_url}/transaction/process"
currency_code = (currency or self.settings.DEFAULT_CURRENCY_SYMBOL or "RUB").upper()
@@ -98,7 +134,7 @@ class PlategaService:
clean_body = {k: v for k, v in body.items() if v not in (None, "")}
try:
async with session.post(url, json=clean_body, headers=self._auth_headers) as response:
async with http_session.post(url, json=clean_body, headers=self._auth_headers) as response:
response_text = await response.text()
try:
response_data = json.loads(response_text) if response_text else {}
+38 -2
View File
@@ -99,12 +99,48 @@ class SeverPayService:
amount: float,
currency: Optional[str],
description: str,
promo_code_service=None,
session=None,
) -> Tuple[bool, Dict[str, Any]]:
if not self.configured:
logging.error("SeverPayService is not configured. Cannot create payment.")
return False, {"message": "service_not_configured"}
session = await self._get_session()
# Check for active discount to save metadata (price already discounted from previous step)
original_amount = None
discount_amount = None
promo_code_id = None
if promo_code_service and session:
from db.dal import active_discount_dal
active_discount = await active_discount_dal.get_active_discount(session, user_id)
if active_discount:
# Price is already discounted, calculate original price backwards
discount_pct = active_discount.discount_percentage
original_amount = amount / (1 - discount_pct / 100)
discount_amount = original_amount - amount
promo_code_id = active_discount.promo_code_id
logging.info(
f"Recording {discount_pct}% discount for SeverPay payment: "
f"original {original_amount:.2f} -> final {amount}"
)
# Update payment record with discount metadata
try:
await payment_dal.update_payment_discount_info(
session,
payment_db_id,
original_amount,
discount_amount,
promo_code_id,
)
await session.commit()
except Exception as e_update:
logging.warning(
f"SeverPay: failed to update discount metadata for payment {payment_db_id}: {e_update}"
)
http_session = await self._get_session()
url = f"{self.base_url}/payin/create"
currency_code = (currency or self.settings.DEFAULT_CURRENCY_SYMBOL or "RUB").upper()
amount_str = self._format_amount(amount)
@@ -124,7 +160,7 @@ class SeverPayService:
signed_body = self._build_signed_body(body)
try:
async with session.post(url, json=signed_body) as response:
async with http_session.post(url, json=signed_body) as response:
response_text = await response.text()
try:
response_data = json.loads(response_text) if response_text else {}
+26
View File
@@ -176,6 +176,32 @@ async def update_provider_payment_and_status(
return payment
async def update_payment_discount_info(
session: AsyncSession,
payment_db_id: int,
original_amount: Optional[float],
discount_applied: Optional[float],
promo_code_id: Optional[int]) -> Optional[Payment]:
"""Update payment record with discount metadata."""
payment = await get_payment_by_db_id(session, payment_db_id)
if payment:
payment.original_amount = original_amount
payment.discount_applied = discount_applied
payment.promo_code_id = promo_code_id
payment.updated_at = func.now()
await session.flush()
await session.refresh(payment)
logging.info(
f"Payment record {payment.payment_id} updated with discount info: "
f"original {original_amount}, discount {discount_applied}, promo {promo_code_id}"
)
else:
logging.warning(
f"Payment record with DB ID {payment_db_id} not found for discount info update."
)
return payment
async def get_financial_statistics(session: AsyncSession) -> Dict[str, Any]:
"""Get comprehensive financial statistics."""
from datetime import datetime, timedelta