Merge pull request #18 from 3252a8/feature/multicurrency
Add ability to use different currency than rub
This commit is contained in:
@@ -12,11 +12,12 @@ from __future__ import annotations
|
||||
import html
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Sequence, Tuple
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
from bot.middlewares.i18n import JsonI18n, get_i18n_instance, normalize_locale_language_code
|
||||
from config.settings import Settings
|
||||
if TYPE_CHECKING:
|
||||
from bot.middlewares.i18n import JsonI18n
|
||||
from config.settings import Settings
|
||||
|
||||
_BG = "#05070a"
|
||||
_CARD_BG = "#0e1116"
|
||||
@@ -64,14 +65,16 @@ def _brand_title(settings: Settings) -> str:
|
||||
|
||||
|
||||
def _normalize_lang(language_code: Optional[str], settings: Settings) -> str:
|
||||
return normalize_locale_language_code(
|
||||
language_code or settings.DEFAULT_LANGUAGE or "ru",
|
||||
prefer_known_base=False,
|
||||
)
|
||||
value = str(language_code or settings.DEFAULT_LANGUAGE or "ru").strip().lower()
|
||||
return value.replace("_", "-") or "ru"
|
||||
|
||||
|
||||
def _resolve_i18n(i18n: Optional[JsonI18n]) -> JsonI18n:
|
||||
return i18n or get_i18n_instance()
|
||||
if i18n is not None:
|
||||
return i18n
|
||||
from bot.middlewares.i18n import get_i18n_instance
|
||||
|
||||
return get_i18n_instance()
|
||||
|
||||
|
||||
def _t_html(i18n: JsonI18n, lang: str, key: str, **kwargs) -> str:
|
||||
|
||||
@@ -11,7 +11,11 @@ from bot.middlewares.i18n import JsonI18n
|
||||
from bot.utils.config_link import prepare_config_links
|
||||
from bot.utils.date_utils import add_months, month_start
|
||||
from config.settings import Settings
|
||||
from config.tariffs_config import Tariff
|
||||
from config.tariffs_config import (
|
||||
Tariff,
|
||||
default_currency_key_for_settings,
|
||||
default_payment_currency_code_for_settings,
|
||||
)
|
||||
from db.dal import (
|
||||
payment_dal,
|
||||
promo_code_dal,
|
||||
|
||||
@@ -70,7 +70,7 @@ class HwidDeviceMixin:
|
||||
package_set = tariff.hwid_device_packages
|
||||
if not package_set:
|
||||
return None
|
||||
packages = package_set.for_currency("stars" if currency == "stars" else "rub")
|
||||
packages = package_set.for_currency(currency)
|
||||
return next((pkg for pkg in packages if int(pkg.count) == int(device_count)), None)
|
||||
|
||||
def _quote_hwid_package_price(
|
||||
@@ -173,7 +173,7 @@ class HwidDeviceMixin:
|
||||
valid_from=valid_from,
|
||||
valid_until=valid_until,
|
||||
now=now,
|
||||
currency="stars" if currency == "stars" else "rub",
|
||||
currency=currency,
|
||||
)
|
||||
quote.update(
|
||||
{
|
||||
@@ -227,7 +227,11 @@ class HwidDeviceMixin:
|
||||
)
|
||||
return None
|
||||
packages = (
|
||||
[*tariff.hwid_device_packages.rub, *tariff.hwid_device_packages.stars]
|
||||
[
|
||||
package
|
||||
for currency_packages in tariff.hwid_device_packages.root.values()
|
||||
for package in currency_packages
|
||||
]
|
||||
if tariff.hwid_device_packages
|
||||
else []
|
||||
)
|
||||
|
||||
@@ -248,9 +248,9 @@ class SubscriptionLifecycleMixin:
|
||||
traffic_used_bytes=used_sub,
|
||||
)
|
||||
update_data["period_start_at"] = None
|
||||
update_data["effective_monthly_price_rub"] = (
|
||||
target.period_price(1, "rub") or target.min_period_price_rub()
|
||||
)
|
||||
update_data["effective_monthly_price_rub"] = target.period_price(
|
||||
1, default_currency_key_for_settings(self.settings)
|
||||
) or target.min_period_price(default_currency_key_for_settings(self.settings))
|
||||
if mode == "recalc_days" and options.get("recalc_days") is not None:
|
||||
update_data["end_date"] = now + timedelta(days=int(options["recalc_days"]))
|
||||
else:
|
||||
|
||||
@@ -120,7 +120,7 @@ class PaymentContextMixin:
|
||||
months=int(months or 0),
|
||||
traffic_gb=traffic_gb,
|
||||
amount=float(payment_amount or 0),
|
||||
currency=self.settings.DEFAULT_CURRENCY_SYMBOL,
|
||||
currency=default_payment_currency_code_for_settings(self.settings),
|
||||
end_date_text=end_date_text,
|
||||
dashboard_url=dashboard_url,
|
||||
provider_label=provider_label,
|
||||
|
||||
@@ -41,7 +41,23 @@ class RenewalMixin:
|
||||
return False
|
||||
|
||||
months = sub.duration_months or 1
|
||||
amount = self.settings.subscription_options.get(months)
|
||||
currency = default_payment_currency_code_for_settings(self.settings)
|
||||
amount = None
|
||||
tariffs_config = (
|
||||
self._tariffs_config() if callable(getattr(self, "_tariffs_config", None)) else None
|
||||
)
|
||||
if tariffs_config and callable(getattr(self, "_resolve_tariff", None)):
|
||||
try:
|
||||
tariff = self._resolve_tariff(getattr(sub, "tariff_key", None))
|
||||
except Exception:
|
||||
tariff = None
|
||||
if tariff and tariff.billing_model == "period":
|
||||
amount = tariff.period_price(
|
||||
months,
|
||||
default_currency_key_for_settings(self.settings),
|
||||
)
|
||||
if amount is None:
|
||||
amount = self.settings.subscription_options.get(months)
|
||||
if not amount:
|
||||
logging.error(f"Auto-renew price missing for {months} months")
|
||||
return False
|
||||
@@ -53,7 +69,7 @@ class RenewalMixin:
|
||||
}
|
||||
resp = await yk.create_payment(
|
||||
amount=float(amount),
|
||||
currency="RUB",
|
||||
currency=currency,
|
||||
description=f"Auto-renewal for {months} months",
|
||||
metadata=metadata,
|
||||
payment_method_id=default_pm.provider_payment_method_id,
|
||||
|
||||
@@ -330,11 +330,12 @@ class TariffMixin:
|
||||
remaining_days = max(0, (sub.end_date - now).days) if sub.end_date else 0
|
||||
effective = float(sub.effective_monthly_price_rub or 0)
|
||||
current_model = current_tariff.billing_model if current_tariff else "period"
|
||||
default_currency = default_currency_key_for_settings(self.settings)
|
||||
|
||||
if current_model == "period" and target_tariff.billing_model == "period":
|
||||
target_monthly = (
|
||||
target_tariff.period_price(1, "rub")
|
||||
or target_tariff.min_period_price_rub()
|
||||
target_tariff.period_price(1, default_currency)
|
||||
or target_tariff.min_period_price(default_currency)
|
||||
or effective
|
||||
or 1
|
||||
)
|
||||
@@ -354,11 +355,14 @@ class TariffMixin:
|
||||
"remaining_days": remaining_days,
|
||||
"recalc_days": max(0, days_after),
|
||||
"paid_diff_rub": paid_diff,
|
||||
"paid_diff": paid_diff,
|
||||
"target_monthly_rub": float(target_monthly),
|
||||
"target_monthly_price": float(target_monthly),
|
||||
"currency": default_currency,
|
||||
}
|
||||
|
||||
if current_model == "period" and target_tariff.billing_model == "traffic":
|
||||
rub_per_gb = target_tariff.rub_per_gb_for_conversion()
|
||||
rub_per_gb = target_tariff.currency_per_gb_for_conversion(default_currency)
|
||||
remaining_value = remaining_days * (effective / 30) if effective else 0
|
||||
converted_gb = math.floor(remaining_value / rub_per_gb) if rub_per_gb else 0
|
||||
return {
|
||||
@@ -366,9 +370,15 @@ class TariffMixin:
|
||||
"remaining_days": remaining_days,
|
||||
"converted_gb": max(0, converted_gb),
|
||||
"rub_per_gb": rub_per_gb,
|
||||
"currency_per_gb": rub_per_gb,
|
||||
"currency": default_currency,
|
||||
}
|
||||
|
||||
return {"mode": "traffic_to_period", "remaining_days": remaining_days}
|
||||
return {
|
||||
"mode": "traffic_to_period",
|
||||
"remaining_days": remaining_days,
|
||||
"currency": default_currency,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _aware_utc(value: Optional[datetime]) -> Optional[datetime]:
|
||||
@@ -433,6 +443,7 @@ class TariffMixin:
|
||||
credit = await self._hwid_conversion_credit(session, sub, at=now)
|
||||
value_rub = float(credit.get("value_rub") or 0)
|
||||
options["converted_hwid_value_rub"] = round(value_rub, 2)
|
||||
options["converted_hwid_value"] = round(value_rub, 2)
|
||||
options["convertible_hwid_purchase_ids"] = list(credit.get("purchase_ids") or [])
|
||||
options["nonconverted_hwid_devices"] = int(credit.get("skipped_devices") or 0)
|
||||
if value_rub <= 0:
|
||||
|
||||
Reference in New Issue
Block a user