RPU v2, promo/bank система, админка, оптимизации

— RPU v2: бюджет удачи, потолок (ceiling), комбек после
  проигрышей, hot/cold анализ, интеграция с promo-фазами
— Bank API: mock-банк для карты (депозит/вывод с балансом 1000₽)
— Promo-сервис: автогенерация промокодов каждый час, типы
  (card_to_site, luck_boost, ceiling_boost, free_case, reset_streak)
— Promo-фазы: LUCKY/NEUTRAL/UNLUCKY, переключение каждые 1-6ч
— Admin: история транзакций (user_history), управление промокодами,
  управление promo-фазами, API фильтров/коллекций, RPU info
— Database: WAL mode, новые поля RPU v2, TransactionLog,
  карточный баланс, статистики (streaks, ceiling, budget)
— Frontend: /deposit, /promo/activate, /withdraw, /card-balance,
  /online-count, /rpu-info, lifespan вместо startup event
— UI: user_history.html, улучшения профиля, кейсов, навигации
— Cases: обновление cases.json (1892 строки новых данных)
— Achievements: кэш коллекций, оптимизация is_custom проверок
— Sounds: дополнительные звуковые эффекты
— Upgrade: интеграция с RPU (множители, streaks)
— .gitignore: исключены .db, .bak, __pycache__
This commit is contained in:
2026-07-25 13:11:08 +00:00
parent 6638ab99f3
commit 47c7f17c90
30 changed files with 5862 additions and 1295 deletions
+107
View File
@@ -0,0 +1,107 @@
"""
BankAPI — внешний сервис для управления "картой" пользователя.
Сейчас заглушка (mock), архитектура под настоящий REST.
"""
import random
from datetime import datetime, timedelta
from typing import Optional
class BankAPIClient:
"""
Клиент для взаимодействия с Bank API.
В будущем — HTTP-клиент к внешнему сервису.
Сейчас — in-memory заглушка.
"""
def __init__(self, base_url: str = "http://bank-api:8000"):
self.base_url = base_url
# mock: user_id -> {balance, transactions}
self._mock_balances: dict[int, float] = {}
self._mock_txns: dict[int, list] = {}
self._initial_balance = 1000.0
def _ensure_user(self, user_id: int):
if user_id not in self._mock_balances:
self._mock_balances[user_id] = self._initial_balance
self._mock_txns[user_id] = []
async def get_balance(self, user_id: int) -> float:
"""Сколько денег на карте пользователя"""
self._ensure_user(user_id)
return self._mock_balances[user_id]
async def transfer_to_site(self, user_id: int, amount: float,
promo_code: Optional[str] = None) -> dict:
"""
Перевод с карты на баланс сайта.
Возвращает: {success, amount, new_card_balance, promo_effect}
"""
self._ensure_user(user_id)
if self._mock_balances[user_id] < amount:
return {"success": False, "error": "Недостаточно средств на карте"}
self._mock_balances[user_id] -= amount
self._mock_txns[user_id].append({
"type": "card_to_site",
"amount": amount,
"promo": promo_code,
"timestamp": datetime.utcnow().isoformat()
})
return {
"success": True,
"amount": amount,
"new_card_balance": self._mock_balances[user_id],
"promo_effect": None
}
async def withdraw_to_card(self, user_id: int, amount: float) -> dict:
"""
Вывод с баланса сайта на карту.
Возвращает: {success, amount, new_card_balance, fee}
"""
self._ensure_user(user_id)
fee = round(amount * 0.10, 2) # 10% комиссия
net = round(amount - fee, 2)
self._mock_balances[user_id] += net
self._mock_txns[user_id].append({
"type": "site_to_card",
"gross": amount,
"fee": fee,
"net": net,
"timestamp": datetime.utcnow().isoformat()
})
return {
"success": True,
"amount": amount,
"fee": fee,
"net": net,
"new_card_balance": self._mock_balances[user_id]
}
async def validate_promo(self, user_id: int, promo_code: str) -> dict:
"""
Проверяет промокод. Возвращает его эффект для перевода card->site.
"""
# Заглушка — реальная логика будет в PromoCode сервисе
return {
"valid": True,
"promo_type": "card_to_site",
"amount": 0,
"luck_boost": 0,
"ceiling_boost": 0
}
async def get_transaction_history(self, user_id: int,
limit: int = 50) -> list:
"""История транзакций по карте"""
self._ensure_user(user_id)
return self._mock_txns[user_id][-limit:]
# Singleton
bank_client = BankAPIClient()