mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
- Добавлено восстановление описания чека из настроек при обработке очереди - Передача telegram_user_id и amount_kopeks через всю цепочку создания чеков - Переход на локальную исправленную версию библ
236 lines
6.7 KiB
Python
236 lines
6.7 KiB
Python
"""
|
|
Main client facade for Moy Nalog API.
|
|
Based on PHP library's ApiClient class.
|
|
"""
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from ._http import AsyncHTTPClient
|
|
from .auth import AuthProviderImpl
|
|
from .income import IncomeAPI
|
|
from .payment_type import PaymentTypeAPI
|
|
from .receipt import ReceiptAPI
|
|
from .tax import TaxAPI
|
|
from .user import UserAPI
|
|
|
|
|
|
class Client:
|
|
"""
|
|
Main async client for Moy Nalog API.
|
|
|
|
Provides factory methods for API modules and authentication methods.
|
|
Maps to PHP ApiClient functionality with async support.
|
|
|
|
Example:
|
|
>>> client = Client()
|
|
>>> token = await client.create_new_access_token("inn", "password")
|
|
>>> await client.authenticate(token)
|
|
>>> income_api = client.income()
|
|
>>> result = await income_api.create("Service", 100, 1)
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
base_url: str = "https://lknpd.nalog.ru/api",
|
|
storage_path: str | None = None,
|
|
device_id: str | None = None,
|
|
timeout: float = 10.0,
|
|
):
|
|
"""
|
|
Initialize Moy Nalog API client.
|
|
|
|
Args:
|
|
base_url: API base URL (default: https://lknpd.nalog.ru/api)
|
|
storage_path: Optional file path for token storage
|
|
device_id: Optional device ID (auto-generated if not provided)
|
|
timeout: HTTP request timeout in seconds
|
|
"""
|
|
self.base_url = base_url
|
|
self.timeout = timeout
|
|
|
|
# Initialize auth provider
|
|
self.auth_provider = AuthProviderImpl(
|
|
base_url=base_url,
|
|
storage_path=storage_path,
|
|
device_id=device_id,
|
|
)
|
|
|
|
# Initialize HTTP client with auth middleware
|
|
self.http_client = AsyncHTTPClient(
|
|
base_url=f"{base_url}/v1",
|
|
auth_provider=self.auth_provider,
|
|
default_headers={
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json, text/plain, */*",
|
|
"Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
|
|
"Referrer": "https://lknpd.nalog.ru/auth/login",
|
|
},
|
|
timeout=timeout,
|
|
)
|
|
|
|
# User profile data (for receipt operations)
|
|
self._user_profile: dict[str, Any] | None = None
|
|
|
|
async def create_new_access_token(self, username: str, password: str) -> str:
|
|
"""
|
|
Create new access token using INN and password.
|
|
|
|
Maps to PHP ApiClient::createNewAccessToken().
|
|
|
|
Args:
|
|
username: INN (tax identification number)
|
|
password: Password
|
|
|
|
Returns:
|
|
JSON string with access token data
|
|
|
|
Raises:
|
|
UnauthorizedException: For invalid credentials
|
|
DomainException: For other API errors
|
|
"""
|
|
return await self.auth_provider.create_new_access_token(username, password)
|
|
|
|
async def create_phone_challenge(self, phone: str) -> dict[str, Any]:
|
|
"""
|
|
Start phone-based authentication challenge.
|
|
|
|
Maps to PHP ApiClient::createPhoneChallenge().
|
|
|
|
Args:
|
|
phone: Phone number (e.g., "79000000000")
|
|
|
|
Returns:
|
|
Dictionary with challengeToken, expireDate, expireIn
|
|
|
|
Raises:
|
|
DomainException: For API errors
|
|
"""
|
|
return await self.auth_provider.create_phone_challenge(phone)
|
|
|
|
async def create_new_access_token_by_phone(
|
|
self, phone: str, challenge_token: str, verification_code: str
|
|
) -> str:
|
|
"""
|
|
Complete phone-based authentication with SMS code.
|
|
|
|
Maps to PHP ApiClient::createNewAccessTokenByPhone().
|
|
|
|
Args:
|
|
phone: Phone number
|
|
challenge_token: Token from create_phone_challenge()
|
|
verification_code: SMS verification code
|
|
|
|
Returns:
|
|
JSON string with access token data
|
|
|
|
Raises:
|
|
UnauthorizedException: For invalid verification
|
|
DomainException: For other API errors
|
|
"""
|
|
return await self.auth_provider.create_new_access_token_by_phone(
|
|
phone, challenge_token, verification_code
|
|
)
|
|
|
|
async def authenticate(self, access_token: str) -> None:
|
|
"""
|
|
Authenticate client with access token.
|
|
|
|
Maps to PHP ApiClient::authenticate().
|
|
|
|
Args:
|
|
access_token: JSON string with token data
|
|
|
|
Raises:
|
|
ValueError: For invalid token JSON
|
|
"""
|
|
await self.auth_provider.set_token(access_token)
|
|
|
|
# Parse token to extract user profile (like PHP version)
|
|
try:
|
|
token_data = json.loads(access_token)
|
|
if "profile" in token_data:
|
|
self._user_profile = token_data["profile"]
|
|
except json.JSONDecodeError:
|
|
# If token parsing fails, profile will remain None
|
|
pass
|
|
|
|
async def get_access_token(self) -> str | None:
|
|
"""
|
|
Get current access token (may be refreshed).
|
|
|
|
Maps to PHP ApiClient::getAccessToken().
|
|
|
|
Returns:
|
|
Current access token JSON string or None
|
|
"""
|
|
token_data = await self.auth_provider.get_token()
|
|
if token_data:
|
|
return json.dumps(token_data)
|
|
return None
|
|
|
|
def income(self) -> IncomeAPI:
|
|
"""
|
|
Get Income API instance.
|
|
|
|
Maps to PHP ApiClient::income().
|
|
|
|
Returns:
|
|
IncomeAPI instance for creating/cancelling receipts
|
|
"""
|
|
return IncomeAPI(self.http_client)
|
|
|
|
def receipt(self) -> ReceiptAPI:
|
|
"""
|
|
Get Receipt API instance.
|
|
|
|
Maps to PHP ApiClient::receipt().
|
|
|
|
Returns:
|
|
ReceiptAPI instance for accessing receipt data
|
|
|
|
Raises:
|
|
ValueError: If user is not authenticated (no profile data)
|
|
"""
|
|
if not self._user_profile or "inn" not in self._user_profile:
|
|
raise ValueError("User profile not available. Please authenticate first.")
|
|
|
|
return ReceiptAPI(
|
|
http_client=self.http_client,
|
|
base_endpoint=self.base_url,
|
|
user_inn=self._user_profile["inn"],
|
|
)
|
|
|
|
def payment_type(self) -> PaymentTypeAPI:
|
|
"""
|
|
Get PaymentType API instance.
|
|
|
|
Maps to PHP ApiClient::paymentType().
|
|
|
|
Returns:
|
|
PaymentTypeAPI instance for managing payment methods
|
|
"""
|
|
return PaymentTypeAPI(self.http_client)
|
|
|
|
def tax(self) -> TaxAPI:
|
|
"""
|
|
Get Tax API instance.
|
|
|
|
Maps to PHP ApiClient::tax().
|
|
|
|
Returns:
|
|
TaxAPI instance for tax information and history
|
|
"""
|
|
return TaxAPI(self.http_client)
|
|
|
|
def user(self) -> UserAPI:
|
|
"""
|
|
Get User API instance.
|
|
|
|
Maps to PHP ApiClient::user().
|
|
|
|
Returns:
|
|
UserAPI instance for user information
|
|
"""
|
|
return UserAPI(self.http_client)
|