mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-05-02 02:36:26 +00:00
Revert "Update miniapp purchase UI to reflect promo pricing"
This commit is contained in:
@@ -57,11 +57,6 @@ from app.services.payment_service import PaymentService
|
||||
from app.services.promo_offer_service import promo_offer_service
|
||||
from app.services.promocode_service import PromoCodeService
|
||||
from app.services.subscription_service import SubscriptionService
|
||||
from app.services.subscription_purchase_service import (
|
||||
purchase_service,
|
||||
PurchaseBalanceError,
|
||||
PurchaseValidationError,
|
||||
)
|
||||
from app.services.tribute_service import TributeService
|
||||
from app.utils.currency_converter import currency_converter
|
||||
from app.utils.subscription_utils import get_happ_cryptolink_redirect_link
|
||||
@@ -131,12 +126,6 @@ from ..schemas.miniapp import (
|
||||
MiniAppSubscriptionTrafficUpdateRequest,
|
||||
MiniAppSubscriptionDevicesUpdateRequest,
|
||||
MiniAppSubscriptionUpdateResponse,
|
||||
MiniAppSubscriptionPurchaseOptionsRequest,
|
||||
MiniAppSubscriptionPurchaseOptionsResponse,
|
||||
MiniAppSubscriptionPurchasePreviewRequest,
|
||||
MiniAppSubscriptionPurchasePreviewResponse,
|
||||
MiniAppSubscriptionPurchaseRequest,
|
||||
MiniAppSubscriptionPurchaseResponse,
|
||||
)
|
||||
|
||||
|
||||
@@ -243,45 +232,6 @@ def _build_balance_invoice_payload(user_id: int, amount_kopeks: int) -> str:
|
||||
return f"balance_{user_id}_{amount_kopeks}_{suffix}"
|
||||
|
||||
|
||||
def _merge_purchase_selection_from_request(
|
||||
payload: Union[
|
||||
"MiniAppSubscriptionPurchasePreviewRequest",
|
||||
"MiniAppSubscriptionPurchaseRequest",
|
||||
]
|
||||
) -> Dict[str, Any]:
|
||||
base: Dict[str, Any] = {}
|
||||
if payload.selection:
|
||||
base.update(payload.selection)
|
||||
|
||||
def _maybe_set(key: str, value: Any) -> None:
|
||||
if value is None:
|
||||
return
|
||||
if key not in base:
|
||||
base[key] = value
|
||||
|
||||
_maybe_set("period_id", getattr(payload, "period_id", None))
|
||||
_maybe_set("period_days", getattr(payload, "period_days", None))
|
||||
|
||||
_maybe_set("traffic_value", getattr(payload, "traffic_value", None))
|
||||
_maybe_set("traffic", getattr(payload, "traffic", None))
|
||||
_maybe_set("traffic_gb", getattr(payload, "traffic_gb", None))
|
||||
|
||||
servers = getattr(payload, "servers", None)
|
||||
if servers is not None and "servers" not in base:
|
||||
base["servers"] = servers
|
||||
countries = getattr(payload, "countries", None)
|
||||
if countries is not None and "countries" not in base:
|
||||
base["countries"] = countries
|
||||
server_uuids = getattr(payload, "server_uuids", None)
|
||||
if server_uuids is not None and "server_uuids" not in base:
|
||||
base["server_uuids"] = server_uuids
|
||||
|
||||
_maybe_set("devices", getattr(payload, "devices", None))
|
||||
_maybe_set("device_limit", getattr(payload, "device_limit", None))
|
||||
|
||||
return base
|
||||
|
||||
|
||||
def _parse_client_timestamp(value: Optional[Union[str, int, float]]) -> Optional[datetime]:
|
||||
if value is None:
|
||||
return None
|
||||
@@ -3144,113 +3094,6 @@ async def _build_subscription_settings(
|
||||
return settings_payload
|
||||
|
||||
|
||||
@router.post(
|
||||
"/subscription/purchase/options",
|
||||
response_model=MiniAppSubscriptionPurchaseOptionsResponse,
|
||||
)
|
||||
async def get_subscription_purchase_options_endpoint(
|
||||
payload: MiniAppSubscriptionPurchaseOptionsRequest,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
) -> MiniAppSubscriptionPurchaseOptionsResponse:
|
||||
user = await _authorize_miniapp_user(payload.init_data, db)
|
||||
context = await purchase_service.build_options(db, user)
|
||||
|
||||
data_payload = dict(context.payload)
|
||||
data_payload.setdefault("currency", context.currency)
|
||||
data_payload.setdefault("balance_kopeks", context.balance_kopeks)
|
||||
data_payload.setdefault("balanceKopeks", context.balance_kopeks)
|
||||
data_payload.setdefault("balance_label", settings.format_price(context.balance_kopeks))
|
||||
data_payload.setdefault("balanceLabel", settings.format_price(context.balance_kopeks))
|
||||
|
||||
return MiniAppSubscriptionPurchaseOptionsResponse(
|
||||
currency=context.currency,
|
||||
balance_kopeks=context.balance_kopeks,
|
||||
balance_label=settings.format_price(context.balance_kopeks),
|
||||
subscription_id=data_payload.get("subscription_id") or data_payload.get("subscriptionId"),
|
||||
data=data_payload,
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/subscription/purchase/preview",
|
||||
response_model=MiniAppSubscriptionPurchasePreviewResponse,
|
||||
)
|
||||
async def subscription_purchase_preview_endpoint(
|
||||
payload: MiniAppSubscriptionPurchasePreviewRequest,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
) -> MiniAppSubscriptionPurchasePreviewResponse:
|
||||
user = await _authorize_miniapp_user(payload.init_data, db)
|
||||
context = await purchase_service.build_options(db, user)
|
||||
|
||||
selection_payload = _merge_purchase_selection_from_request(payload)
|
||||
try:
|
||||
selection = purchase_service.parse_selection(context, selection_payload)
|
||||
except PurchaseValidationError as error:
|
||||
raise HTTPException(
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
detail={"code": error.code, "message": str(error)},
|
||||
) from error
|
||||
|
||||
pricing = await purchase_service.calculate_pricing(db, context, selection)
|
||||
preview_payload = purchase_service.build_preview_payload(context, pricing)
|
||||
|
||||
balance_label = settings.format_price(getattr(user, "balance_kopeks", 0))
|
||||
|
||||
return MiniAppSubscriptionPurchasePreviewResponse(
|
||||
preview=preview_payload,
|
||||
balance_kopeks=user.balance_kopeks,
|
||||
balance_label=balance_label,
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/subscription/purchase",
|
||||
response_model=MiniAppSubscriptionPurchaseResponse,
|
||||
)
|
||||
async def subscription_purchase_endpoint(
|
||||
payload: MiniAppSubscriptionPurchaseRequest,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
) -> MiniAppSubscriptionPurchaseResponse:
|
||||
user = await _authorize_miniapp_user(payload.init_data, db)
|
||||
context = await purchase_service.build_options(db, user)
|
||||
|
||||
selection_payload = _merge_purchase_selection_from_request(payload)
|
||||
try:
|
||||
selection = purchase_service.parse_selection(context, selection_payload)
|
||||
except PurchaseValidationError as error:
|
||||
raise HTTPException(
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
detail={"code": error.code, "message": str(error)},
|
||||
) from error
|
||||
|
||||
pricing = await purchase_service.calculate_pricing(db, context, selection)
|
||||
|
||||
try:
|
||||
result = await purchase_service.submit_purchase(db, context, pricing)
|
||||
except PurchaseBalanceError as error:
|
||||
raise HTTPException(
|
||||
status.HTTP_402_PAYMENT_REQUIRED,
|
||||
detail={"code": "insufficient_funds", "message": str(error)},
|
||||
) from error
|
||||
except PurchaseValidationError as error:
|
||||
raise HTTPException(
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
detail={"code": error.code, "message": str(error)},
|
||||
) from error
|
||||
|
||||
await db.refresh(user)
|
||||
|
||||
subscription = result.get("subscription")
|
||||
balance_label = settings.format_price(getattr(user, "balance_kopeks", 0))
|
||||
|
||||
return MiniAppSubscriptionPurchaseResponse(
|
||||
message=result.get("message"),
|
||||
balance_kopeks=user.balance_kopeks,
|
||||
balance_label=balance_label,
|
||||
subscription_id=getattr(subscription, "id", None),
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/subscription/settings",
|
||||
response_model=MiniAppSubscriptionSettingsResponse,
|
||||
|
||||
@@ -524,88 +524,3 @@ class MiniAppSubscriptionUpdateResponse(BaseModel):
|
||||
success: bool = True
|
||||
message: Optional[str] = None
|
||||
|
||||
|
||||
class MiniAppSubscriptionPurchaseOptionsRequest(BaseModel):
|
||||
init_data: str = Field(..., alias="initData")
|
||||
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
|
||||
class MiniAppSubscriptionPurchaseOptionsResponse(BaseModel):
|
||||
success: bool = True
|
||||
currency: str
|
||||
balance_kopeks: Optional[int] = Field(default=None, alias="balanceKopeks")
|
||||
balance_label: Optional[str] = Field(default=None, alias="balanceLabel")
|
||||
subscription_id: Optional[int] = Field(default=None, alias="subscriptionId")
|
||||
data: Dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
|
||||
class MiniAppSubscriptionPurchasePreviewRequest(BaseModel):
|
||||
init_data: str = Field(..., alias="initData")
|
||||
subscription_id: Optional[int] = Field(default=None, alias="subscriptionId")
|
||||
selection: Optional[Dict[str, Any]] = None
|
||||
period_id: Optional[str] = Field(default=None, alias="periodId")
|
||||
period_days: Optional[int] = Field(default=None, alias="periodDays")
|
||||
period: Optional[str] = None
|
||||
traffic_value: Optional[int] = Field(default=None, alias="trafficValue")
|
||||
traffic: Optional[int] = None
|
||||
traffic_gb: Optional[int] = Field(default=None, alias="trafficGb")
|
||||
servers: Optional[List[str]] = None
|
||||
countries: Optional[List[str]] = None
|
||||
server_uuids: Optional[List[str]] = Field(default=None, alias="serverUuids")
|
||||
devices: Optional[int] = None
|
||||
device_limit: Optional[int] = Field(default=None, alias="deviceLimit")
|
||||
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def _merge_selection(cls, values: Any) -> Any:
|
||||
if not isinstance(values, dict):
|
||||
return values
|
||||
selection = values.get("selection")
|
||||
if isinstance(selection, dict):
|
||||
merged = {**selection, **values}
|
||||
else:
|
||||
merged = dict(values)
|
||||
aliases = {
|
||||
"period_id": ("periodId", "period", "code"),
|
||||
"period_days": ("periodDays",),
|
||||
"traffic_value": ("trafficValue", "traffic", "trafficGb"),
|
||||
"servers": ("countries", "server_uuids", "serverUuids"),
|
||||
"devices": ("deviceLimit",),
|
||||
}
|
||||
for target, sources in aliases.items():
|
||||
if merged.get(target) is not None:
|
||||
continue
|
||||
for source in sources:
|
||||
if source in merged and merged[source] is not None:
|
||||
merged[target] = merged[source]
|
||||
break
|
||||
return merged
|
||||
|
||||
|
||||
class MiniAppSubscriptionPurchasePreviewResponse(BaseModel):
|
||||
success: bool = True
|
||||
preview: Dict[str, Any] = Field(default_factory=dict)
|
||||
balance_kopeks: Optional[int] = Field(default=None, alias="balanceKopeks")
|
||||
balance_label: Optional[str] = Field(default=None, alias="balanceLabel")
|
||||
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
|
||||
class MiniAppSubscriptionPurchaseRequest(MiniAppSubscriptionPurchasePreviewRequest):
|
||||
pass
|
||||
|
||||
|
||||
class MiniAppSubscriptionPurchaseResponse(BaseModel):
|
||||
success: bool = True
|
||||
message: Optional[str] = None
|
||||
balance_kopeks: Optional[int] = Field(default=None, alias="balanceKopeks")
|
||||
balance_label: Optional[str] = Field(default=None, alias="balanceLabel")
|
||||
subscription_id: Optional[int] = Field(default=None, alias="subscriptionId")
|
||||
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user