2c3ffc8c8a
Full integration across bot, cabinet, admin panel and landing pages: - Config: 16 OVERPAY_* settings (API URL, credentials, P12 cert path, project ID, currency, amount limits, webhook path, payment methods) - Service: overpay_service.py with httpx mTLS (P12 cert) + Basic Auth, create_payment, get_payment, refund_payment methods - Payment mixin: OverpayPaymentMixin with create, webhook processing, finalize (balance credit + notifications), status check - Model: OverpayPayment table + OVERPAY enum value - CRUD: 9 standard operations (create, get_by_*, for_update, link) - Bot handler: start_overpay_topup + process_overpay_payment_amount - Handler registration: route_payment_by_method + callback registration - Webhook: POST /overpay-webhook with DB-based anti-spoofing validation - Cabinet: balance topup + guest payment dispatch - Keyboard: payment method button in bot - Admin: settings category + test payment button - Infrastructure: payment_method_config_service, system_settings_service, payment_verification_service, payment_search_service - Migration 0064: create overpay_payments table Overpay API specifics: amount as string "100.00" (not kopeks), success status "charged", HPP redirect via resultUrl
46 lines
1.9 KiB
Python
46 lines
1.9 KiB
Python
"""create overpay_payments table
|
|
|
|
Revision ID: 0064
|
|
Revises: 0063
|
|
Create Date: 2026-04-21
|
|
|
|
"""
|
|
|
|
from typing import Sequence, Union
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision: str = '0064'
|
|
down_revision: Union[str, None] = '0063'
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
|
depends_on: Union[str, Sequence[str], None] = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.create_table(
|
|
'overpay_payments',
|
|
sa.Column('id', sa.Integer(), primary_key=True, autoincrement=True),
|
|
sa.Column('user_id', sa.Integer(), sa.ForeignKey('users.id', ondelete='SET NULL'), nullable=True, index=True),
|
|
sa.Column('order_id', sa.String(64), unique=True, nullable=False, index=True),
|
|
sa.Column('overpay_payment_id', sa.String(128), unique=True, nullable=True, index=True),
|
|
sa.Column('amount_kopeks', sa.Integer(), nullable=False),
|
|
sa.Column('currency', sa.String(10), nullable=False, server_default='RUB'),
|
|
sa.Column('description', sa.Text(), nullable=True),
|
|
sa.Column('status', sa.String(32), nullable=False, server_default='pending'),
|
|
sa.Column('is_paid', sa.Boolean(), server_default=sa.text('false'), nullable=False),
|
|
sa.Column('payment_url', sa.Text(), nullable=True),
|
|
sa.Column('payment_method', sa.String(32), nullable=True),
|
|
sa.Column('metadata_json', sa.JSON(), nullable=True),
|
|
sa.Column('callback_payload', sa.JSON(), nullable=True),
|
|
sa.Column('paid_at', sa.DateTime(timezone=True), nullable=True),
|
|
sa.Column('expires_at', sa.DateTime(timezone=True), nullable=True),
|
|
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.func.now()),
|
|
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.func.now()),
|
|
sa.Column('transaction_id', sa.Integer(), sa.ForeignKey('transactions.id'), nullable=True),
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_table('overpay_payments')
|