Implement buy flow and migrate DTOs to schemas

Move DTO definitions from dto/ to schemas/ and update imports.
Add buy handler with FSM state management for device selection,
whitelist toggling, and duration choice. Include pricing logic,
inline keyboards, and new configuration fields.
This commit is contained in:
2026-04-08 19:34:25 +07:00
parent fc45816eba
commit 930fabc028
17 changed files with 291 additions and 50 deletions

View File

@@ -1,7 +1,9 @@
from typing import Optional
from random import choice
from datetime import datetime, timezone
from datetime import datetime, timedelta, timezone
from config import settings
from schemas.subscriptions import SubscriptionDuration, SubscriptionPlan
import texts
QUOTES: list[str] = [
@@ -125,3 +127,45 @@ def format_username(username: Optional[str]) -> str:
if username:
return "@" + username
return texts.NO_USERNAME
def convert_duration_to_int(duration: SubscriptionDuration) -> int:
mapping: dict[str, int] = {
SubscriptionDuration.MONTH.value: 1,
SubscriptionDuration.THREE_MONTHS.value: 3,
SubscriptionDuration.SIX_MONTHS.value: 6,
SubscriptionDuration.YEAR.value: 12,
}
return mapping.get(duration.value, 1)
def convert_int_to_duration(value: int) -> SubscriptionDuration:
mapping: dict[int, SubscriptionDuration] = {
1: SubscriptionDuration.MONTH,
3: SubscriptionDuration.THREE_MONTHS,
6: SubscriptionDuration.SIX_MONTHS,
12: SubscriptionDuration.YEAR,
}
return mapping.get(value, SubscriptionDuration.MONTH)
def convert_duration_to_timedelta(duration: SubscriptionDuration) -> timedelta:
MONTH_DELTA = timedelta(days=30)
mapping: dict[str, timedelta] = {
SubscriptionDuration.MONTH.value: MONTH_DELTA,
SubscriptionDuration.THREE_MONTHS.value: MONTH_DELTA * 3,
SubscriptionDuration.SIX_MONTHS.value: MONTH_DELTA * 6,
SubscriptionDuration.YEAR.value: MONTH_DELTA * 12,
}
return mapping.get(duration.value, MONTH_DELTA)
def calculate_price(subscription: SubscriptionPlan):
return (
(subscription.devices * settings.per_device_cost)
+ (
int(subscription.whitelists) * settings.whitelist_cost
if subscription.devices < settings.whitelist_device_threshold
else 0
)
) * convert_duration_to_int(subscription.duration)