mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-21 11:51:06 +00:00
Revert "feat: add promo group addon discount toggle"
This commit is contained in:
@@ -60,7 +60,6 @@ async def create_promo_group(
|
||||
device_discount_percent: int,
|
||||
period_discounts: Optional[Dict[int, int]] = None,
|
||||
auto_assign_total_spent_kopeks: Optional[int] = None,
|
||||
addon_discounts_enabled: bool = True,
|
||||
) -> PromoGroup:
|
||||
normalized_period_discounts = _normalize_period_discounts(period_discounts)
|
||||
|
||||
@@ -70,8 +69,6 @@ async def create_promo_group(
|
||||
else None
|
||||
)
|
||||
|
||||
addon_discounts_enabled = bool(addon_discounts_enabled)
|
||||
|
||||
promo_group = PromoGroup(
|
||||
name=name.strip(),
|
||||
server_discount_percent=max(0, min(100, server_discount_percent)),
|
||||
@@ -79,7 +76,6 @@ async def create_promo_group(
|
||||
device_discount_percent=max(0, min(100, device_discount_percent)),
|
||||
period_discounts=normalized_period_discounts or None,
|
||||
auto_assign_total_spent_kopeks=auto_assign_total_spent_kopeks,
|
||||
addon_discounts_enabled=addon_discounts_enabled,
|
||||
is_default=False,
|
||||
)
|
||||
|
||||
@@ -88,15 +84,13 @@ async def create_promo_group(
|
||||
await db.refresh(promo_group)
|
||||
|
||||
logger.info(
|
||||
"Создана промогруппа '%s' с скидками (servers=%s%%, traffic=%s%%, devices=%s%%, periods=%s)"
|
||||
" и порогом автоприсвоения %s₽ (скидки на доп. услуги: %s)",
|
||||
"Создана промогруппа '%s' с скидками (servers=%s%%, traffic=%s%%, devices=%s%%, periods=%s) и порогом автоприсвоения %s₽",
|
||||
promo_group.name,
|
||||
promo_group.server_discount_percent,
|
||||
promo_group.traffic_discount_percent,
|
||||
promo_group.device_discount_percent,
|
||||
normalized_period_discounts,
|
||||
(auto_assign_total_spent_kopeks or 0) / 100,
|
||||
addon_discounts_enabled,
|
||||
)
|
||||
|
||||
return promo_group
|
||||
@@ -112,7 +106,6 @@ async def update_promo_group(
|
||||
device_discount_percent: Optional[int] = None,
|
||||
period_discounts: Optional[Dict[int, int]] = None,
|
||||
auto_assign_total_spent_kopeks: Optional[int] = None,
|
||||
addon_discounts_enabled: Optional[bool] = None,
|
||||
) -> PromoGroup:
|
||||
if name is not None:
|
||||
group.name = name.strip()
|
||||
@@ -127,8 +120,6 @@ async def update_promo_group(
|
||||
group.period_discounts = normalized_period_discounts or None
|
||||
if auto_assign_total_spent_kopeks is not None:
|
||||
group.auto_assign_total_spent_kopeks = max(0, auto_assign_total_spent_kopeks)
|
||||
if addon_discounts_enabled is not None:
|
||||
group.addon_discounts_enabled = bool(addon_discounts_enabled)
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(group)
|
||||
|
||||
@@ -292,7 +292,6 @@ class PromoGroup(Base):
|
||||
device_discount_percent = Column(Integer, nullable=False, default=0)
|
||||
period_discounts = Column(JSON, nullable=True, default=dict)
|
||||
auto_assign_total_spent_kopeks = Column(Integer, nullable=True, default=None)
|
||||
addon_discounts_enabled = Column(Boolean, nullable=False, default=True)
|
||||
is_default = Column(Boolean, nullable=False, default=False)
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
|
||||
@@ -347,16 +346,7 @@ class PromoGroup(Base):
|
||||
|
||||
return 0
|
||||
|
||||
def get_discount_percent(
|
||||
self,
|
||||
category: str,
|
||||
period_days: Optional[int] = None,
|
||||
*,
|
||||
for_addon: bool = False,
|
||||
) -> int:
|
||||
if for_addon and category != "period" and not self.addon_discounts_enabled:
|
||||
return 0
|
||||
|
||||
def get_discount_percent(self, category: str, period_days: Optional[int] = None) -> int:
|
||||
if category == "period":
|
||||
return max(0, min(100, self._get_period_discount(period_days)))
|
||||
|
||||
@@ -414,20 +404,10 @@ class User(Base):
|
||||
parts = [self.first_name, self.last_name]
|
||||
return " ".join(filter(None, parts)) or self.username or f"ID{self.telegram_id}"
|
||||
|
||||
def get_promo_discount(
|
||||
self,
|
||||
category: str,
|
||||
period_days: Optional[int] = None,
|
||||
*,
|
||||
for_addon: bool = False,
|
||||
) -> int:
|
||||
def get_promo_discount(self, category: str, period_days: Optional[int] = None) -> int:
|
||||
if not self.promo_group:
|
||||
return 0
|
||||
return self.promo_group.get_discount_percent(
|
||||
category,
|
||||
period_days,
|
||||
for_addon=for_addon,
|
||||
)
|
||||
return self.promo_group.get_discount_percent(category, period_days)
|
||||
|
||||
def add_balance(self, kopeks: int) -> None:
|
||||
self.balance_kopeks += kopeks
|
||||
|
||||
@@ -931,44 +931,6 @@ async def ensure_promo_groups_setup():
|
||||
"Добавлена колонка promo_groups.auto_assign_total_spent_kopeks"
|
||||
)
|
||||
|
||||
addon_discounts_column_exists = await check_column_exists(
|
||||
"promo_groups", "addon_discounts_enabled"
|
||||
)
|
||||
|
||||
if not addon_discounts_column_exists:
|
||||
if db_type == "sqlite":
|
||||
await conn.execute(
|
||||
text(
|
||||
"ALTER TABLE promo_groups ADD COLUMN addon_discounts_enabled BOOLEAN NOT NULL DEFAULT 1"
|
||||
)
|
||||
)
|
||||
await conn.execute(
|
||||
text(
|
||||
"UPDATE promo_groups SET addon_discounts_enabled = 1 WHERE addon_discounts_enabled IS NULL"
|
||||
)
|
||||
)
|
||||
elif db_type == "postgresql":
|
||||
await conn.execute(
|
||||
text(
|
||||
"ALTER TABLE promo_groups ADD COLUMN addon_discounts_enabled BOOLEAN NOT NULL DEFAULT TRUE"
|
||||
)
|
||||
)
|
||||
elif db_type == "mysql":
|
||||
await conn.execute(
|
||||
text(
|
||||
"ALTER TABLE promo_groups ADD COLUMN addon_discounts_enabled TINYINT(1) NOT NULL DEFAULT 1"
|
||||
)
|
||||
)
|
||||
else:
|
||||
logger.error(
|
||||
f"Неподдерживаемый тип БД для promo_groups.addon_discounts_enabled: {db_type}"
|
||||
)
|
||||
return False
|
||||
|
||||
logger.info(
|
||||
"Добавлена колонка promo_groups.addon_discounts_enabled"
|
||||
)
|
||||
|
||||
column_exists = await check_column_exists("users", "promo_group_id")
|
||||
|
||||
if not column_exists:
|
||||
@@ -2032,7 +1994,6 @@ async def check_migration_status():
|
||||
"users_promo_group_column": False,
|
||||
"promo_groups_period_discounts_column": False,
|
||||
"promo_groups_auto_assign_column": False,
|
||||
"promo_groups_addon_discounts_column": False,
|
||||
"users_auto_promo_group_assigned_column": False,
|
||||
"subscription_crypto_link_column": False,
|
||||
}
|
||||
@@ -2050,7 +2011,6 @@ async def check_migration_status():
|
||||
status["users_promo_group_column"] = await check_column_exists('users', 'promo_group_id')
|
||||
status["promo_groups_period_discounts_column"] = await check_column_exists('promo_groups', 'period_discounts')
|
||||
status["promo_groups_auto_assign_column"] = await check_column_exists('promo_groups', 'auto_assign_total_spent_kopeks')
|
||||
status["promo_groups_addon_discounts_column"] = await check_column_exists('promo_groups', 'addon_discounts_enabled')
|
||||
status["users_auto_promo_group_assigned_column"] = await check_column_exists('users', 'auto_promo_group_assigned')
|
||||
status["subscription_crypto_link_column"] = await check_column_exists('subscriptions', 'subscription_crypto_link')
|
||||
|
||||
@@ -2088,7 +2048,6 @@ async def check_migration_status():
|
||||
"users_promo_group_column": "Колонка promo_group_id у пользователей",
|
||||
"promo_groups_period_discounts_column": "Колонка period_discounts у промо-групп",
|
||||
"promo_groups_auto_assign_column": "Колонка auto_assign_total_spent_kopeks у промо-групп",
|
||||
"promo_groups_addon_discounts_column": "Колонка addon_discounts_enabled у промо-групп",
|
||||
"users_auto_promo_group_assigned_column": "Флаг автоназначения промогруппы у пользователей",
|
||||
"subscription_crypto_link_column": "Колонка subscription_crypto_link в subscriptions",
|
||||
}
|
||||
|
||||
@@ -190,21 +190,6 @@ def _format_auto_assign_line(texts, group: PromoGroup) -> str:
|
||||
).format(amount=amount)
|
||||
|
||||
|
||||
def _format_addon_discount_line(texts, group: PromoGroup) -> str:
|
||||
enabled = getattr(group, "addon_discounts_enabled", True)
|
||||
key = (
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_ENABLED"
|
||||
if enabled
|
||||
else "ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_DISABLED"
|
||||
)
|
||||
default = (
|
||||
"Скидки на доп. услуги: включены"
|
||||
if enabled
|
||||
else "Скидки на доп. услуги: отключены"
|
||||
)
|
||||
return texts.t(key, default)
|
||||
|
||||
|
||||
def _format_auto_assign_value(value_kopeks: Optional[int]) -> str:
|
||||
if not value_kopeks or value_kopeks <= 0:
|
||||
return "0"
|
||||
@@ -238,20 +223,6 @@ def _parse_auto_assign_threshold_input(value: str) -> int:
|
||||
return max(0, kopeks)
|
||||
|
||||
|
||||
def _parse_addon_discount_input(value: str) -> bool:
|
||||
normalized = (value or "").strip().lower()
|
||||
|
||||
truthy = {"1", "true", "on", "yes", "да", "вкл", "y"}
|
||||
falsy = {"0", "false", "off", "no", "нет", "выкл", "n"}
|
||||
|
||||
if normalized in truthy:
|
||||
return True
|
||||
if normalized in falsy:
|
||||
return False
|
||||
|
||||
raise ValueError
|
||||
|
||||
|
||||
async def _prompt_for_auto_assign_threshold(
|
||||
message: types.Message,
|
||||
state: FSMContext,
|
||||
@@ -273,27 +244,6 @@ async def _prompt_for_auto_assign_threshold(
|
||||
await message.answer(prompt_text)
|
||||
|
||||
|
||||
async def _prompt_for_addon_discount(
|
||||
message: types.Message,
|
||||
state: FSMContext,
|
||||
prompt_key: str,
|
||||
default_text: str,
|
||||
*,
|
||||
current_value: Optional[str] = None,
|
||||
):
|
||||
data = await state.get_data()
|
||||
texts = get_texts(data.get("language", "ru"))
|
||||
prompt_text = texts.t(prompt_key, default_text)
|
||||
|
||||
if current_value is not None:
|
||||
try:
|
||||
prompt_text = prompt_text.format(current=current_value)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
await message.answer(prompt_text)
|
||||
|
||||
|
||||
def _build_edit_menu_content(
|
||||
texts,
|
||||
group: PromoGroup,
|
||||
@@ -307,7 +257,6 @@ def _build_edit_menu_content(
|
||||
lines = [
|
||||
header,
|
||||
_format_discount_line(texts, group),
|
||||
_format_addon_discount_line(texts, group),
|
||||
_format_auto_assign_line(texts, group),
|
||||
]
|
||||
|
||||
@@ -360,15 +309,6 @@ def _build_edit_menu_content(
|
||||
callback_data=f"promo_group_edit_field_{group.id}_devices",
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.t(
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_ADDON",
|
||||
"💡 Скидки на доп. услуги",
|
||||
),
|
||||
callback_data=f"promo_group_edit_field_{group.id}_addon",
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.t(
|
||||
@@ -459,7 +399,6 @@ async def show_promo_groups_menu(
|
||||
group_lines = [
|
||||
f"{'⭐' if group.is_default else '🎯'} <b>{group.name}</b>{default_suffix}",
|
||||
_format_discount_line(texts, group),
|
||||
_format_addon_discount_line(texts, group),
|
||||
_format_auto_assign_line(texts, group),
|
||||
texts.t(
|
||||
"ADMIN_PROMO_GROUPS_MEMBERS_COUNT",
|
||||
@@ -736,39 +675,6 @@ async def process_create_group_period_discounts(
|
||||
return
|
||||
|
||||
await state.update_data(new_group_period_discounts=period_discounts)
|
||||
await state.set_state(AdminStates.creating_promo_group_addon_discounts)
|
||||
|
||||
await _prompt_for_addon_discount(
|
||||
message,
|
||||
state,
|
||||
"ADMIN_PROMO_GROUP_CREATE_ADDON_PROMPT",
|
||||
"Включить скидки на доп. услуги при докупке? Отправьте 1 для включения или 0 для отключения.",
|
||||
)
|
||||
|
||||
|
||||
@admin_required
|
||||
@error_handler
|
||||
async def process_create_group_addon_discounts(
|
||||
message: types.Message,
|
||||
state: FSMContext,
|
||||
db_user,
|
||||
db: AsyncSession,
|
||||
):
|
||||
data = await state.get_data()
|
||||
texts = get_texts(data.get("language", db_user.language))
|
||||
|
||||
try:
|
||||
addon_enabled = _parse_addon_discount_input(message.text)
|
||||
except ValueError:
|
||||
await message.answer(
|
||||
texts.t(
|
||||
"ADMIN_PROMO_GROUP_INVALID_ADDON",
|
||||
"Введите 1, чтобы включить скидки, или 0, чтобы отключить.",
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
await state.update_data(new_group_addon_discounts=addon_enabled)
|
||||
await state.set_state(AdminStates.creating_promo_group_auto_assign)
|
||||
|
||||
await _prompt_for_auto_assign_threshold(
|
||||
@@ -810,7 +716,6 @@ async def process_create_group_auto_assign(
|
||||
device_discount_percent=data["new_group_devices"],
|
||||
period_discounts=data.get("new_group_period_discounts"),
|
||||
auto_assign_total_spent_kopeks=auto_assign_kopeks,
|
||||
addon_discounts_enabled=data.get("new_group_addon_discounts", True),
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Не удалось создать промогруппу: {e}")
|
||||
@@ -914,12 +819,6 @@ async def prompt_edit_promo_group_field(
|
||||
"ADMIN_PROMO_GROUP_EDIT_DEVICES_PROMPT",
|
||||
"Введите новую скидку на устройства (текущее значение: {current}%):",
|
||||
).format(current=group.device_discount_percent)
|
||||
elif field == "addon":
|
||||
await state.set_state(AdminStates.editing_promo_group_addon_discounts)
|
||||
prompt = texts.t(
|
||||
"ADMIN_PROMO_GROUP_EDIT_ADDON_PROMPT",
|
||||
"Отправьте 1 для включения скидок на доп. услуги или 0 для отключения. Сейчас: {current}.",
|
||||
).format(current=_format_addon_discount_line(texts, group))
|
||||
elif field == "periods":
|
||||
await state.set_state(AdminStates.editing_promo_group_period_discount)
|
||||
current_discounts = _normalize_periods_dict(getattr(group, "period_discounts", None))
|
||||
@@ -1045,56 +944,6 @@ async def process_edit_group_servers(
|
||||
)
|
||||
|
||||
|
||||
@admin_required
|
||||
@error_handler
|
||||
async def process_edit_group_addon_discounts(
|
||||
message: types.Message,
|
||||
state: FSMContext,
|
||||
db_user,
|
||||
db: AsyncSession,
|
||||
):
|
||||
data = await state.get_data()
|
||||
texts = get_texts(data.get("language", db_user.language))
|
||||
|
||||
try:
|
||||
addon_enabled = _parse_addon_discount_input(message.text)
|
||||
except ValueError:
|
||||
await message.answer(
|
||||
texts.t(
|
||||
"ADMIN_PROMO_GROUP_INVALID_ADDON",
|
||||
"Введите 1, чтобы включить скидки, или 0, чтобы отключить.",
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
group = await get_promo_group_by_id(db, data.get("edit_group_id"))
|
||||
if not group:
|
||||
await message.answer("❌ Промогруппа не найдена")
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
group = await update_promo_group(
|
||||
db,
|
||||
group,
|
||||
addon_discounts_enabled=addon_enabled,
|
||||
)
|
||||
await state.set_state(AdminStates.editing_promo_group_menu)
|
||||
|
||||
success_key = (
|
||||
"ADMIN_PROMO_GROUP_ADDON_ENABLED_SUCCESS"
|
||||
if addon_enabled
|
||||
else "ADMIN_PROMO_GROUP_ADDON_DISABLED_SUCCESS"
|
||||
)
|
||||
|
||||
await _send_edit_menu_after_update(
|
||||
message,
|
||||
texts,
|
||||
group,
|
||||
data.get("language", db_user.language),
|
||||
texts.t(success_key, "Скидки на доп. услуги обновлены."),
|
||||
)
|
||||
|
||||
|
||||
@admin_required
|
||||
@error_handler
|
||||
async def process_edit_group_devices(
|
||||
@@ -1386,10 +1235,6 @@ def register_handlers(dp: Dispatcher):
|
||||
process_create_group_period_discounts,
|
||||
AdminStates.creating_promo_group_period_discount,
|
||||
)
|
||||
dp.message.register(
|
||||
process_create_group_addon_discounts,
|
||||
AdminStates.creating_promo_group_addon_discounts,
|
||||
)
|
||||
dp.message.register(
|
||||
process_create_group_auto_assign,
|
||||
AdminStates.creating_promo_group_auto_assign,
|
||||
@@ -1404,10 +1249,6 @@ def register_handlers(dp: Dispatcher):
|
||||
process_edit_group_servers,
|
||||
AdminStates.editing_promo_group_server_discount,
|
||||
)
|
||||
dp.message.register(
|
||||
process_edit_group_addon_discounts,
|
||||
AdminStates.editing_promo_group_addon_discounts,
|
||||
)
|
||||
dp.message.register(
|
||||
process_edit_group_devices,
|
||||
AdminStates.editing_promo_group_device_discount,
|
||||
|
||||
@@ -1251,11 +1251,7 @@ async def apply_countries_changes(
|
||||
db: AsyncSession,
|
||||
state: FSMContext
|
||||
):
|
||||
from app.utils.pricing_utils import (
|
||||
get_remaining_months,
|
||||
calculate_prorated_price,
|
||||
apply_percentage_discount,
|
||||
)
|
||||
from app.utils.pricing_utils import get_remaining_months, calculate_prorated_price
|
||||
|
||||
logger.info(f"🔧 Применение изменений стран")
|
||||
|
||||
@@ -1296,38 +1292,23 @@ async def apply_countries_changes(
|
||||
cost_per_month = 0
|
||||
added_names = []
|
||||
removed_names = []
|
||||
|
||||
|
||||
added_server_prices = []
|
||||
servers_discount_percent = db_user.get_promo_discount(
|
||||
"servers",
|
||||
for_addon=True,
|
||||
)
|
||||
discounted_prices_by_uuid: Dict[str, int] = {}
|
||||
|
||||
|
||||
for country in countries:
|
||||
if country['uuid'] in added:
|
||||
server_price_per_month = country['price_kopeks']
|
||||
discounted_per_month = server_price_per_month
|
||||
if servers_discount_percent:
|
||||
discounted_per_month, _ = apply_percentage_discount(
|
||||
server_price_per_month,
|
||||
servers_discount_percent,
|
||||
)
|
||||
discounted_prices_by_uuid[country['uuid']] = discounted_per_month
|
||||
cost_per_month += discounted_per_month
|
||||
cost_per_month += server_price_per_month
|
||||
added_names.append(country['name'])
|
||||
if country['uuid'] in removed:
|
||||
removed_names.append(country['name'])
|
||||
|
||||
|
||||
total_cost, charged_months = calculate_prorated_price(cost_per_month, subscription.end_date)
|
||||
|
||||
|
||||
for country in countries:
|
||||
if country['uuid'] in added:
|
||||
discounted_per_month = discounted_prices_by_uuid.get(
|
||||
country['uuid'],
|
||||
country['price_kopeks'],
|
||||
)
|
||||
server_total_price = discounted_per_month * charged_months
|
||||
server_price_per_month = country['price_kopeks']
|
||||
server_total_price = server_price_per_month * charged_months
|
||||
added_server_prices.append(server_total_price)
|
||||
|
||||
logger.info(f"Стоимость новых серверов: {cost_per_month/100}₽/мес × {charged_months} мес = {total_cost/100}₽")
|
||||
@@ -1512,11 +1493,7 @@ async def confirm_change_devices(
|
||||
db_user: User,
|
||||
db: AsyncSession
|
||||
):
|
||||
from app.utils.pricing_utils import (
|
||||
get_remaining_months,
|
||||
calculate_prorated_price,
|
||||
apply_percentage_discount,
|
||||
)
|
||||
from app.utils.pricing_utils import get_remaining_months, calculate_prorated_price
|
||||
|
||||
new_devices_count = int(callback.data.split('_')[2])
|
||||
texts = get_texts(db_user.language)
|
||||
@@ -1547,15 +1524,6 @@ async def confirm_change_devices(
|
||||
chargeable_devices = additional_devices
|
||||
|
||||
devices_price_per_month = chargeable_devices * settings.PRICE_PER_DEVICE
|
||||
devices_discount_percent = db_user.get_promo_discount(
|
||||
"devices",
|
||||
for_addon=True,
|
||||
)
|
||||
if devices_discount_percent:
|
||||
devices_price_per_month, _ = apply_percentage_discount(
|
||||
devices_price_per_month,
|
||||
devices_discount_percent,
|
||||
)
|
||||
price, charged_months = calculate_prorated_price(devices_price_per_month, subscription.end_date)
|
||||
|
||||
if price > 0 and db_user.balance_kopeks < price:
|
||||
@@ -1616,11 +1584,7 @@ async def execute_change_devices(
|
||||
db_user: User,
|
||||
db: AsyncSession
|
||||
):
|
||||
from app.utils.pricing_utils import (
|
||||
get_remaining_months,
|
||||
calculate_prorated_price,
|
||||
apply_percentage_discount,
|
||||
)
|
||||
from app.utils.pricing_utils import get_remaining_months, calculate_prorated_price
|
||||
|
||||
callback_parts = callback.data.split('_')
|
||||
new_devices_count = int(callback_parts[3])
|
||||
@@ -2156,7 +2120,7 @@ async def confirm_add_devices(
|
||||
db_user: User,
|
||||
db: AsyncSession
|
||||
):
|
||||
from app.utils.pricing_utils import get_remaining_months, apply_percentage_discount
|
||||
from app.utils.pricing_utils import get_remaining_months, calculate_prorated_price
|
||||
|
||||
devices_count = int(callback.data.split('_')[2])
|
||||
texts = get_texts(db_user.language)
|
||||
@@ -2175,15 +2139,6 @@ async def confirm_add_devices(
|
||||
return
|
||||
|
||||
devices_price_per_month = devices_count * settings.PRICE_PER_DEVICE
|
||||
devices_discount_percent = db_user.get_promo_discount(
|
||||
"devices",
|
||||
for_addon=True,
|
||||
)
|
||||
if devices_discount_percent:
|
||||
devices_price_per_month, _ = apply_percentage_discount(
|
||||
devices_price_per_month,
|
||||
devices_discount_percent,
|
||||
)
|
||||
price, charged_months = calculate_prorated_price(devices_price_per_month, subscription.end_date)
|
||||
|
||||
logger.info(f"Добавление {devices_count} устройств: {devices_price_per_month/100}₽/мес × {charged_months} мес = {price/100}₽")
|
||||
@@ -3541,20 +3496,12 @@ async def add_traffic(
|
||||
if settings.is_traffic_fixed():
|
||||
await callback.answer("⚠️ В текущем режиме трафик фиксированный", show_alert=True)
|
||||
return
|
||||
|
||||
|
||||
traffic_gb = int(callback.data.split('_')[2])
|
||||
texts = get_texts(db_user.language)
|
||||
subscription = db_user.subscription
|
||||
|
||||
|
||||
price = settings.get_traffic_price(traffic_gb)
|
||||
traffic_discount_percent = db_user.get_promo_discount(
|
||||
"traffic",
|
||||
for_addon=True,
|
||||
)
|
||||
if traffic_discount_percent:
|
||||
from app.utils.pricing_utils import apply_percentage_discount
|
||||
|
||||
price, _ = apply_percentage_discount(price, traffic_discount_percent)
|
||||
|
||||
if price == 0 and traffic_gb != 0:
|
||||
await callback.answer("⚠️ Цена для этого пакета не настроена", show_alert=True)
|
||||
@@ -4953,7 +4900,7 @@ async def confirm_switch_traffic(
|
||||
db_user: User,
|
||||
db: AsyncSession
|
||||
):
|
||||
from app.utils.pricing_utils import get_remaining_months, apply_percentage_discount
|
||||
from app.utils.pricing_utils import get_remaining_months, calculate_prorated_price
|
||||
|
||||
new_traffic_gb = int(callback.data.split('_')[2])
|
||||
texts = get_texts(db_user.language)
|
||||
@@ -4967,19 +4914,6 @@ async def confirm_switch_traffic(
|
||||
|
||||
old_price_per_month = settings.get_traffic_price(current_traffic)
|
||||
new_price_per_month = settings.get_traffic_price(new_traffic_gb)
|
||||
traffic_discount_percent = db_user.get_promo_discount(
|
||||
"traffic",
|
||||
for_addon=True,
|
||||
)
|
||||
if traffic_discount_percent:
|
||||
old_price_per_month, _ = apply_percentage_discount(
|
||||
old_price_per_month,
|
||||
traffic_discount_percent,
|
||||
)
|
||||
new_price_per_month, _ = apply_percentage_discount(
|
||||
new_price_per_month,
|
||||
traffic_discount_percent,
|
||||
)
|
||||
|
||||
months_remaining = get_remaining_months(subscription.end_date)
|
||||
price_difference_per_month = new_price_per_month - old_price_per_month
|
||||
|
||||
@@ -163,22 +163,14 @@
|
||||
"ADMIN_PROMO_GROUP_CREATE_TRAFFIC_PROMPT": "Enter traffic discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_SERVERS_PROMPT": "Enter server discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_DEVICES_PROMPT": "Enter device discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_ADDON_PROMPT": "Enable discounts for add-on services? Send 1 to enable or 0 to disable.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_PERCENT": "Enter a number from 0 to 100.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_ADDON": "Send 1 to enable discounts or 0 to disable them.",
|
||||
"ADMIN_PROMO_GROUP_CREATED": "Promo group “{name}” created.",
|
||||
"ADMIN_PROMO_GROUP_CREATED_BACK_BUTTON": "↩️ Back to promo groups",
|
||||
"ADMIN_PROMO_GROUP_EDIT_NAME_PROMPT": "Enter a new name (current: {name}):",
|
||||
"ADMIN_PROMO_GROUP_EDIT_TRAFFIC_PROMPT": "Enter new traffic discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_EDIT_SERVERS_PROMPT": "Enter new server discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_EDIT_DEVICES_PROMPT": "Enter new device discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_ADDON": "💡 Add-on service discounts",
|
||||
"ADMIN_PROMO_GROUP_EDIT_ADDON_PROMPT": "Send 1 to enable add-on discounts or 0 to disable them. Current: {current}.",
|
||||
"ADMIN_PROMO_GROUP_UPDATED": "Promo group “{name}” updated.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_ENABLED_SUCCESS": "Add-on service discounts enabled.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISABLED_SUCCESS": "Add-on service discounts disabled.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_ENABLED": "Add-on discounts: enabled",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_DISABLED": "Add-on discounts: disabled",
|
||||
"ADMIN_PROMO_GROUP_MEMBERS_TITLE": "👥 Members of {name}",
|
||||
"ADMIN_PROMO_GROUP_MEMBERS_EMPTY": "This group has no members yet.",
|
||||
"ADMIN_PROMO_GROUP_DELETE_FORBIDDEN": "The default promo group cannot be deleted.",
|
||||
|
||||
@@ -40,22 +40,14 @@
|
||||
"ADMIN_PROMO_GROUP_CREATE_TRAFFIC_PROMPT": "Введите скидку на трафик (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_SERVERS_PROMPT": "Введите скидку на серверы (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_DEVICES_PROMPT": "Введите скидку на устройства (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_ADDON_PROMPT": "Включить скидки на доп. услуги при докупке? Отправьте 1 для включения или 0 для отключения.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_PERCENT": "Введите число от 0 до 100.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_ADDON": "Введите 1, чтобы включить скидки, или 0, чтобы отключить.",
|
||||
"ADMIN_PROMO_GROUP_CREATED": "Промогруппа «{name}» создана.",
|
||||
"ADMIN_PROMO_GROUP_CREATED_BACK_BUTTON": "↩️ К промогруппам",
|
||||
"ADMIN_PROMO_GROUP_EDIT_NAME_PROMPT": "Введите новое название промогруппы (текущее: {name}):",
|
||||
"ADMIN_PROMO_GROUP_EDIT_TRAFFIC_PROMPT": "Введите новую скидку на трафик (0-100):",
|
||||
"ADMIN_PROMO_GROUP_EDIT_SERVERS_PROMPT": "Введите новую скидку на серверы (0-100):",
|
||||
"ADMIN_PROMO_GROUP_EDIT_DEVICES_PROMPT": "Введите новую скидку на устройства (0-100):",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_ADDON": "💡 Скидки на доп. услуги",
|
||||
"ADMIN_PROMO_GROUP_EDIT_ADDON_PROMPT": "Отправьте 1 для включения скидок на доп. услуги или 0 для отключения. Сейчас: {current}.",
|
||||
"ADMIN_PROMO_GROUP_UPDATED": "Промогруппа «{name}» обновлена.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_ENABLED_SUCCESS": "Скидки на доп. услуги включены.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISABLED_SUCCESS": "Скидки на доп. услуги отключены.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_ENABLED": "Скидки на доп. услуги: включены",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_DISABLED": "Скидки на доп. услуги: отключены",
|
||||
"ADMIN_PROMO_GROUP_MEMBERS_TITLE": "👥 Участники группы {name}",
|
||||
"ADMIN_PROMO_GROUP_MEMBERS_EMPTY": "В этой группе пока нет участников.",
|
||||
"ADMIN_PROMO_GROUP_DELETE_FORBIDDEN": "Базовую промогруппу нельзя удалить.",
|
||||
|
||||
@@ -26,24 +26,15 @@ def _resolve_discount_percent(
|
||||
category: str,
|
||||
*,
|
||||
period_days: Optional[int] = None,
|
||||
for_addon: bool = False,
|
||||
) -> int:
|
||||
if user is not None:
|
||||
try:
|
||||
return user.get_promo_discount(
|
||||
category,
|
||||
period_days,
|
||||
for_addon=for_addon,
|
||||
)
|
||||
return user.get_promo_discount(category, period_days)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if promo_group is not None:
|
||||
return promo_group.get_discount_percent(
|
||||
category,
|
||||
period_days,
|
||||
for_addon=for_addon,
|
||||
)
|
||||
return promo_group.get_discount_percent(category, period_days)
|
||||
|
||||
return 0
|
||||
|
||||
@@ -872,7 +863,6 @@ class SubscriptionService:
|
||||
promo_group,
|
||||
"traffic",
|
||||
period_days=period_hint_days,
|
||||
for_addon=True,
|
||||
)
|
||||
traffic_discount_per_month = traffic_price_per_month * traffic_discount_percent // 100
|
||||
discounted_traffic_per_month = traffic_price_per_month - traffic_discount_per_month
|
||||
@@ -896,7 +886,6 @@ class SubscriptionService:
|
||||
promo_group,
|
||||
"devices",
|
||||
period_days=period_hint_days,
|
||||
for_addon=True,
|
||||
)
|
||||
devices_discount_per_month = devices_price_per_month * devices_discount_percent // 100
|
||||
discounted_devices_per_month = devices_price_per_month - devices_discount_per_month
|
||||
@@ -924,7 +913,6 @@ class SubscriptionService:
|
||||
promo_group,
|
||||
"servers",
|
||||
period_days=period_hint_days,
|
||||
for_addon=True,
|
||||
)
|
||||
server_discount_per_month = (
|
||||
server_price_per_month * servers_discount_percent // 100
|
||||
|
||||
@@ -69,7 +69,6 @@ class AdminStates(StatesGroup):
|
||||
creating_promo_group_server_discount = State()
|
||||
creating_promo_group_device_discount = State()
|
||||
creating_promo_group_period_discount = State()
|
||||
creating_promo_group_addon_discounts = State()
|
||||
creating_promo_group_auto_assign = State()
|
||||
|
||||
editing_promo_group_menu = State()
|
||||
@@ -78,7 +77,6 @@ class AdminStates(StatesGroup):
|
||||
editing_promo_group_server_discount = State()
|
||||
editing_promo_group_device_discount = State()
|
||||
editing_promo_group_period_discount = State()
|
||||
editing_promo_group_addon_discounts = State()
|
||||
editing_promo_group_auto_assign = State()
|
||||
|
||||
editing_squad_price = State()
|
||||
|
||||
@@ -243,10 +243,8 @@
|
||||
"ADMIN_PROMO_GROUP_CREATE_TRAFFIC_PROMPT": "Enter traffic discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_SERVERS_PROMPT": "Enter server discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_DEVICES_PROMPT": "Enter device discount (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_ADDON_PROMPT": "Enable discounts for add-on services? Send 1 to enable or 0 to disable.",
|
||||
"ADMIN_PROMO_GROUP_CREATE_PERIOD_PROMPT": "Enter subscription period discounts (e.g. 30:10, 90:15). Send 0 if none.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_PERCENT": "Enter a number from 0 to 100.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_ADDON": "Send 1 to enable discounts or 0 to disable them.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_PERIOD_DISCOUNTS": "Enter period:discount pairs separated by commas, e.g. 30:10, 90:15, or 0.",
|
||||
"ADMIN_PROMO_GROUP_CREATED": "Promo group “{name}” created.",
|
||||
"ADMIN_PROMO_GROUP_CREATED_BACK_BUTTON": "↩️ Back to promo groups",
|
||||
@@ -264,17 +262,11 @@
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_TRAFFIC": "🌐 Traffic discount",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_SERVERS": "🖥 Server discount",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_DEVICES": "📱 Device discount",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_ADDON": "💡 Add-on service discounts",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_PERIODS": "⏳ Period discounts",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_AUTO_ASSIGN": "🤖 Auto assignment by spending",
|
||||
"ADMIN_PROMO_GROUP_CREATE_AUTO_ASSIGN_PROMPT": "Enter total spending (in ₽) required for automatic assignment. Send 0 to disable.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_AUTO_ASSIGN": "Enter a non-negative amount in rubles or 0 to disable.",
|
||||
"ADMIN_PROMO_GROUP_EDIT_AUTO_ASSIGN_PROMPT": "Enter total spending (in ₽) for auto assignment. Current value: {current}.",
|
||||
"ADMIN_PROMO_GROUP_EDIT_ADDON_PROMPT": "Send 1 to enable add-on discounts or 0 to disable them. Current: {current}.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_ENABLED_SUCCESS": "Add-on service discounts enabled.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISABLED_SUCCESS": "Add-on service discounts disabled.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_ENABLED": "Add-on discounts: enabled",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_DISABLED": "Add-on discounts: disabled",
|
||||
"ADMIN_PROMO_GROUP_MEMBERS_TITLE": "👥 Members of {name}",
|
||||
"ADMIN_PROMO_GROUP_MEMBERS_EMPTY": "This group has no members yet.",
|
||||
"ADMIN_PROMO_GROUP_DELETE_FORBIDDEN": "The default promo group cannot be deleted.",
|
||||
|
||||
@@ -109,10 +109,8 @@
|
||||
"ADMIN_PROMO_GROUP_CREATE_TRAFFIC_PROMPT": "Введите скидку на трафик (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_SERVERS_PROMPT": "Введите скидку на серверы (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_DEVICES_PROMPT": "Введите скидку на устройства (0-100):",
|
||||
"ADMIN_PROMO_GROUP_CREATE_ADDON_PROMPT": "Включить скидки на доп. услуги при докупке? Отправьте 1 для включения или 0 для отключения.",
|
||||
"ADMIN_PROMO_GROUP_CREATE_PERIOD_PROMPT": "Введите скидки на периоды подписки (например, 30:10, 90:15). Отправьте 0, если без скидок.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_PERCENT": "Введите число от 0 до 100.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_ADDON": "Введите 1, чтобы включить скидки, или 0, чтобы отключить.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_PERIOD_DISCOUNTS": "Введите пары период:скидка через запятую, например 30:10, 90:15, или 0.",
|
||||
"ADMIN_PROMO_GROUP_CREATED": "Промогруппа «{name}» создана.",
|
||||
"ADMIN_PROMO_GROUP_CREATED_BACK_BUTTON": "↩️ К промогруппам",
|
||||
@@ -130,17 +128,11 @@
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_TRAFFIC": "🌐 Скидка на трафик",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_SERVERS": "🖥 Скидка на серверы",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_DEVICES": "📱 Скидка на устройства",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_ADDON": "💡 Скидки на доп. услуги",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_PERIODS": "⏳ Скидки по периодам",
|
||||
"ADMIN_PROMO_GROUP_EDIT_FIELD_AUTO_ASSIGN": "🤖 Автовыдача по тратам",
|
||||
"ADMIN_PROMO_GROUP_CREATE_AUTO_ASSIGN_PROMPT": "Введите сумму общих трат (в ₽) для автоматической выдачи этой группы. Отправьте 0, чтобы отключить.",
|
||||
"ADMIN_PROMO_GROUP_INVALID_AUTO_ASSIGN": "Введите неотрицательное число в рублях или 0 для отключения.",
|
||||
"ADMIN_PROMO_GROUP_EDIT_AUTO_ASSIGN_PROMPT": "Введите сумму общих трат (в ₽) для автовыдачи. Текущее значение: {current}.",
|
||||
"ADMIN_PROMO_GROUP_EDIT_ADDON_PROMPT": "Отправьте 1 для включения скидок на доп. услуги или 0 для отключения. Сейчас: {current}.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_ENABLED_SUCCESS": "Скидки на доп. услуги включены.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISABLED_SUCCESS": "Скидки на доп. услуги отключены.",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_ENABLED": "Скидки на доп. услуги: включены",
|
||||
"ADMIN_PROMO_GROUP_ADDON_DISCOUNTS_DISABLED": "Скидки на доп. услуги: отключены",
|
||||
"ADMIN_PROMO_GROUP_MEMBERS_TITLE": "👥 Участники группы {name}",
|
||||
"ADMIN_PROMO_GROUP_MEMBERS_EMPTY": "В этой группе пока нет участников.",
|
||||
"ADMIN_PROMO_GROUP_DELETE_FORBIDDEN": "Базовую промогруппу нельзя удалить.",
|
||||
|
||||
Reference in New Issue
Block a user