Compare commits
4 Commits
03e6363c1a
...
9a62722a3c
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a62722a3c | |||
| 5d610c484d | |||
| 8cb1ac89a6 | |||
| d1f7612f37 |
@@ -27,6 +27,7 @@ class Settings(BaseSettings):
|
|||||||
remnawave_default_squads_raw: str = Field(alias="REMNAWAVE_DEFAULT_SQUADS_UUIDS")
|
remnawave_default_squads_raw: str = Field(alias="REMNAWAVE_DEFAULT_SQUADS_UUIDS")
|
||||||
|
|
||||||
minimal_deposit: int = Field()
|
minimal_deposit: int = Field()
|
||||||
|
referal_bonus: int = Field(30)
|
||||||
|
|
||||||
@computed_field
|
@computed_field
|
||||||
@property
|
@property
|
||||||
|
|||||||
4
external/pally.py
vendored
4
external/pally.py
vendored
@@ -30,8 +30,8 @@ class Currency(StrEnum):
|
|||||||
|
|
||||||
|
|
||||||
class BillType(StrEnum):
|
class BillType(StrEnum):
|
||||||
NORMAL = "normal"
|
NORMAL = "NORMAL"
|
||||||
MULTI = "multi"
|
MULTI = "MULTI"
|
||||||
|
|
||||||
|
|
||||||
class BillStatus(StrEnum):
|
class BillStatus(StrEnum):
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ async def signup(req: UserRegistration, session: AsyncSession = Depends(get_db))
|
|||||||
username=user.username,
|
username=user.username,
|
||||||
telegram_id=user.telegram_id,
|
telegram_id=user.telegram_id,
|
||||||
referal_code=user.referal_code,
|
referal_code=user.referal_code,
|
||||||
|
bonus_balance=user.balance,
|
||||||
).model_dump(),
|
).model_dump(),
|
||||||
status_code=201,
|
status_code=201,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ from fastapi.routing import APIRouter
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from core.deps import get_db
|
from core.deps import get_db
|
||||||
|
from db.models.transactions import BalanceTransaction, BalanceTxType
|
||||||
from external.pally import BillStatus
|
from external.pally import BillStatus
|
||||||
|
from repositories.invoices import InvoiceRepository
|
||||||
|
from repositories.users import UserRepository
|
||||||
|
from schemas.invoices import InvoiceStatus
|
||||||
from services.payments import process_subscription_purchase, validate_pally_signature
|
from services.payments import process_subscription_purchase, validate_pally_signature
|
||||||
|
|
||||||
router = APIRouter(prefix="/payments/pally")
|
router = APIRouter(prefix="/payments/pally")
|
||||||
@@ -82,11 +86,69 @@ async def pally_callback(
|
|||||||
|
|
||||||
amount = int(float(BalanceAmount)) if BalanceAmount is not None else int(float(OutSum))
|
amount = int(float(BalanceAmount)) if BalanceAmount is not None else int(float(OutSum))
|
||||||
|
|
||||||
|
try:
|
||||||
await process_subscription_purchase(
|
await process_subscription_purchase(
|
||||||
session,
|
session,
|
||||||
invoice_id=int(invoice_id_str),
|
invoice_id=int(invoice_id_str),
|
||||||
trs_id=TrsId,
|
trs_id=TrsId,
|
||||||
amount=amount,
|
amount=amount,
|
||||||
)
|
)
|
||||||
|
except Exception:
|
||||||
|
# The payment is confirmed, so never leave the user without the money
|
||||||
|
# if order/subscription provisioning fails.
|
||||||
|
logger.exception(
|
||||||
|
"Subscription provisioning failed for bill %s (TrsId: %s); "
|
||||||
|
"crediting the user's bonus balance",
|
||||||
|
invoice_id_str,
|
||||||
|
TrsId,
|
||||||
|
)
|
||||||
|
await session.rollback()
|
||||||
|
|
||||||
|
invoice_repo = InvoiceRepository(session)
|
||||||
|
invoice = await invoice_repo.get_by_id(int(invoice_id_str))
|
||||||
|
if invoice is None:
|
||||||
|
logger.critical(
|
||||||
|
"Cannot credit fallback balance: bill %s was not found (TrsId: %s)",
|
||||||
|
invoice_id_str,
|
||||||
|
TrsId,
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
if invoice.status == InvoiceStatus.PAID:
|
||||||
|
return "OK"
|
||||||
|
|
||||||
|
user = await UserRepository(session).get_user_by_id(invoice.creator_id)
|
||||||
|
if user is None:
|
||||||
|
logger.critical(
|
||||||
|
"Cannot credit fallback balance: user %s was not found " "for bill %s (TrsId: %s)",
|
||||||
|
invoice.creator_id,
|
||||||
|
invoice_id_str,
|
||||||
|
TrsId,
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
balance_before = user.balance
|
||||||
|
user.balance += amount
|
||||||
|
invoice.status = InvoiceStatus.PAID
|
||||||
|
session.add(
|
||||||
|
BalanceTransaction(
|
||||||
|
user_id=user.id,
|
||||||
|
amount=amount,
|
||||||
|
tx_type=BalanceTxType.DEPOSIT,
|
||||||
|
balance_before=balance_before,
|
||||||
|
balance_after=user.balance,
|
||||||
|
description=(
|
||||||
|
f"fallback payment credit for invoice {invoice.id} " f"(TrsId: {TrsId})"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await session.commit()
|
||||||
|
logger.info(
|
||||||
|
"Fallback payment credit processed: user_id=%s, amount=%s, " "invoice_id=%s, TrsId=%s",
|
||||||
|
user.id,
|
||||||
|
amount,
|
||||||
|
invoice.id,
|
||||||
|
TrsId,
|
||||||
|
)
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ async def get_me(ctx: AuthContext = Depends(get_auth_context)):
|
|||||||
username=ctx.user.username,
|
username=ctx.user.username,
|
||||||
telegram_id=ctx.user.telegram_id,
|
telegram_id=ctx.user.telegram_id,
|
||||||
referal_code=ctx.user.referal_code,
|
referal_code=ctx.user.referal_code,
|
||||||
|
bonus_balance=ctx.user.balance,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ async def get_subscription(ctx: AuthContext = Depends(get_auth_context)):
|
|||||||
has_subscription=True,
|
has_subscription=True,
|
||||||
devices=sub.devices,
|
devices=sub.devices,
|
||||||
expires_at=sub.expires_at,
|
expires_at=sub.expires_at,
|
||||||
addon_ids=[a.id for a in sub.addons],
|
addon_ids=[a.addon_id for a in sub.addons],
|
||||||
subscription_link=build_subscription_link(rw_user.short_uuid),
|
subscription_link=build_subscription_link(rw_user.short_uuid),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -15,3 +15,4 @@ class UserInfo(BaseModel):
|
|||||||
username: str | None = Field(None)
|
username: str | None = Field(None)
|
||||||
telegram_id: str | None = Field(None)
|
telegram_id: str | None = Field(None)
|
||||||
referal_code: str = Field()
|
referal_code: str = Field()
|
||||||
|
bonus_balance: float = Field()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ async def authorize_user(
|
|||||||
username=user.username,
|
username=user.username,
|
||||||
telegram_id=user.telegram_id,
|
telegram_id=user.telegram_id,
|
||||||
referal_code=user.referal_code,
|
referal_code=user.referal_code,
|
||||||
|
bonus_balance=user.balance,
|
||||||
),
|
),
|
||||||
expires_at=key_pair.expires_at,
|
expires_at=key_pair.expires_at,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user