104 lines
5.7 KiB
Python
104 lines
5.7 KiB
Python
"""Phase 7R.6 PayUMoney online payment gateway
|
|
|
|
Revision ID: 20260606_phase_7r6_payumoney
|
|
Revises: 20260603_phase_7r3_payments
|
|
Create Date: 2026-06-06
|
|
|
|
Adds PayUMoney settings and a small online payment transaction ledger.
|
|
The migration is intentionally defensive for SQLite development databases.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
revision = "20260606_phase_7r6_payumoney"
|
|
down_revision = "20260603_phase_7r3_payments"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def _tables() -> set[str]:
|
|
return set(sa.inspect(op.get_bind()).get_table_names())
|
|
|
|
|
|
def _columns(table_name: str) -> set[str]:
|
|
inspector = sa.inspect(op.get_bind())
|
|
if table_name not in inspector.get_table_names():
|
|
return set()
|
|
return {c["name"] for c in inspector.get_columns(table_name)}
|
|
|
|
|
|
def _add_if_missing(table: str, column: sa.Column) -> None:
|
|
if table in _tables() and column.name not in _columns(table):
|
|
op.add_column(table, column)
|
|
|
|
|
|
def _index_exists(index_name: str) -> bool:
|
|
inspector = sa.inspect(op.get_bind())
|
|
for table_name in inspector.get_table_names():
|
|
for idx in inspector.get_indexes(table_name):
|
|
if idx.get("name") == index_name:
|
|
return True
|
|
return False
|
|
|
|
|
|
def _create_index_if_missing(name: str, table: str, columns: list[str], unique: bool = False) -> None:
|
|
if table in _tables() and not _index_exists(name):
|
|
op.create_index(name, table, columns, unique=unique)
|
|
|
|
|
|
def upgrade() -> None:
|
|
_add_if_missing("billing_settings", sa.Column("payumoney_enabled", sa.Boolean(), nullable=False, server_default=sa.false()))
|
|
_add_if_missing("billing_settings", sa.Column("payumoney_mode", sa.String(length=20), nullable=False, server_default="TEST"))
|
|
_add_if_missing("billing_settings", sa.Column("payumoney_merchant_key", sa.String(length=120), nullable=True))
|
|
_add_if_missing("billing_settings", sa.Column("payumoney_merchant_salt", sa.String(length=200), nullable=True))
|
|
_add_if_missing("billing_settings", sa.Column("payumoney_merchant_id", sa.String(length=120), nullable=True))
|
|
_add_if_missing("billing_settings", sa.Column("payumoney_product_info", sa.String(length=200), nullable=True))
|
|
|
|
if "billing_online_payment_transactions" not in _tables():
|
|
op.create_table(
|
|
"billing_online_payment_transactions",
|
|
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
sa.Column("tenant_id", sa.Integer(), nullable=False),
|
|
sa.Column("branch_id", sa.Integer(), nullable=True),
|
|
sa.Column("invoice_id", sa.Integer(), nullable=False),
|
|
sa.Column("client_id", sa.Integer(), nullable=False),
|
|
sa.Column("provider", sa.String(length=40), nullable=False, server_default="PAYUMONEY"),
|
|
sa.Column("mode", sa.String(length=20), nullable=False, server_default="TEST"),
|
|
sa.Column("txnid", sa.String(length=80), nullable=False),
|
|
sa.Column("amount", sa.Numeric(14, 2), nullable=False, server_default="0.00"),
|
|
sa.Column("productinfo", sa.String(length=250), nullable=True),
|
|
sa.Column("firstname", sa.String(length=120), nullable=True),
|
|
sa.Column("email", sa.String(length=255), nullable=True),
|
|
sa.Column("phone", sa.String(length=50), nullable=True),
|
|
sa.Column("payu_payment_id", sa.String(length=120), nullable=True),
|
|
sa.Column("bank_ref_num", sa.String(length=120), nullable=True),
|
|
sa.Column("mihpayid", sa.String(length=120), nullable=True),
|
|
sa.Column("status", sa.String(length=30), nullable=False, server_default="INITIATED"),
|
|
sa.Column("gateway_status", sa.String(length=80), nullable=True),
|
|
sa.Column("response_hash", sa.String(length=200), nullable=True),
|
|
sa.Column("raw_response", sa.Text(), nullable=True),
|
|
sa.Column("receipt_payment_id", sa.Integer(), nullable=True),
|
|
sa.Column("created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
|
|
sa.Column("updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
|
|
sa.Column("completed_at_utc", sa.DateTime(timezone=True), nullable=True),
|
|
sa.ForeignKeyConstraint(["tenant_id"], ["tenants.id"], ondelete="CASCADE"),
|
|
sa.ForeignKeyConstraint(["branch_id"], ["branches.id"], ondelete="SET NULL"),
|
|
sa.ForeignKeyConstraint(["invoice_id"], ["billing_invoices.id"], ondelete="CASCADE"),
|
|
sa.ForeignKeyConstraint(["client_id"], ["clients.id"], ondelete="RESTRICT"),
|
|
sa.ForeignKeyConstraint(["receipt_payment_id"], ["billing_payments.id"], ondelete="SET NULL"),
|
|
sa.UniqueConstraint("tenant_id", "txnid", name="uq_billing_online_payment_tenant_txnid"),
|
|
)
|
|
_create_index_if_missing("ix_billing_online_payment_transactions_tenant_id", "billing_online_payment_transactions", ["tenant_id"])
|
|
_create_index_if_missing("ix_billing_online_payment_transactions_branch_id", "billing_online_payment_transactions", ["branch_id"])
|
|
_create_index_if_missing("ix_billing_online_payment_transactions_invoice_id", "billing_online_payment_transactions", ["invoice_id"])
|
|
_create_index_if_missing("ix_billing_online_payment_transactions_client_id", "billing_online_payment_transactions", ["client_id"])
|
|
_create_index_if_missing("ix_billing_online_payment_transactions_txnid", "billing_online_payment_transactions", ["txnid"])
|
|
_create_index_if_missing("ix_billing_online_payment_transactions_status", "billing_online_payment_transactions", ["status"])
|
|
|
|
|
|
def downgrade() -> None:
|
|
if "billing_online_payment_transactions" in _tables():
|
|
op.drop_table("billing_online_payment_transactions")
|