fix: auto-fix code issues (cron)
- 修复重复导入/字段 - 修复异常处理 - 修复PEP8格式问题 - 添加类型注解 - 修复缺失的urllib.parse导入
This commit is contained in:
@@ -21,6 +21,7 @@ from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SubscriptionStatus(StrEnum):
|
||||
"""订阅状态"""
|
||||
|
||||
@@ -31,6 +32,7 @@ class SubscriptionStatus(StrEnum):
|
||||
TRIAL = "trial" # 试用中
|
||||
PENDING = "pending" # 待支付
|
||||
|
||||
|
||||
class PaymentProvider(StrEnum):
|
||||
"""支付提供商"""
|
||||
|
||||
@@ -39,6 +41,7 @@ class PaymentProvider(StrEnum):
|
||||
WECHAT = "wechat" # 微信支付
|
||||
BANK_TRANSFER = "bank_transfer" # 银行转账
|
||||
|
||||
|
||||
class PaymentStatus(StrEnum):
|
||||
"""支付状态"""
|
||||
|
||||
@@ -49,6 +52,7 @@ class PaymentStatus(StrEnum):
|
||||
REFUNDED = "refunded" # 已退款
|
||||
PARTIAL_REFUNDED = "partial_refunded" # 部分退款
|
||||
|
||||
|
||||
class InvoiceStatus(StrEnum):
|
||||
"""发票状态"""
|
||||
|
||||
@@ -59,6 +63,7 @@ class InvoiceStatus(StrEnum):
|
||||
VOID = "void" # 作废
|
||||
CREDIT_NOTE = "credit_note" # 贷项通知单
|
||||
|
||||
|
||||
class RefundStatus(StrEnum):
|
||||
"""退款状态"""
|
||||
|
||||
@@ -68,6 +73,7 @@ class RefundStatus(StrEnum):
|
||||
COMPLETED = "completed" # 已完成
|
||||
FAILED = "failed" # 失败
|
||||
|
||||
|
||||
@dataclass
|
||||
class SubscriptionPlan:
|
||||
"""订阅计划数据类"""
|
||||
@@ -86,6 +92,7 @@ class SubscriptionPlan:
|
||||
updated_at: datetime
|
||||
metadata: dict[str, Any]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Subscription:
|
||||
"""订阅数据类"""
|
||||
@@ -106,6 +113,7 @@ class Subscription:
|
||||
updated_at: datetime
|
||||
metadata: dict[str, Any]
|
||||
|
||||
|
||||
@dataclass
|
||||
class UsageRecord:
|
||||
"""用量记录数据类"""
|
||||
@@ -120,6 +128,7 @@ class UsageRecord:
|
||||
description: str | None
|
||||
metadata: dict[str, Any]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Payment:
|
||||
"""支付记录数据类"""
|
||||
@@ -141,6 +150,7 @@ class Payment:
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class Invoice:
|
||||
"""发票数据类"""
|
||||
@@ -164,6 +174,7 @@ class Invoice:
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class Refund:
|
||||
"""退款数据类"""
|
||||
@@ -186,6 +197,7 @@ class Refund:
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class BillingHistory:
|
||||
"""账单历史数据类"""
|
||||
@@ -201,6 +213,7 @@ class BillingHistory:
|
||||
created_at: datetime
|
||||
metadata: dict[str, Any]
|
||||
|
||||
|
||||
class SubscriptionManager:
|
||||
"""订阅与计费管理器"""
|
||||
|
||||
@@ -213,7 +226,13 @@ class SubscriptionManager:
|
||||
"price_monthly": 0.0,
|
||||
"price_yearly": 0.0,
|
||||
"currency": "CNY",
|
||||
"features": ["basic_analysis", "export_png", "3_projects", "100_mb_storage", "60_min_transcription"],
|
||||
"features": [
|
||||
"basic_analysis",
|
||||
"export_png",
|
||||
"3_projects",
|
||||
"100_mb_storage",
|
||||
"60_min_transcription",
|
||||
],
|
||||
"limits": {
|
||||
"max_projects": 3,
|
||||
"max_storage_mb": 100,
|
||||
@@ -280,9 +299,17 @@ class SubscriptionManager:
|
||||
|
||||
# 按量计费单价(CNY)
|
||||
USAGE_PRICING = {
|
||||
"transcription": {"unit": "minute", "price": 0.5, "free_quota": 60}, # 0.5元/分钟 # 每月免费额度
|
||||
"transcription": {
|
||||
"unit": "minute",
|
||||
"price": 0.5,
|
||||
"free_quota": 60,
|
||||
}, # 0.5元/分钟 # 每月免费额度
|
||||
"storage": {"unit": "gb", "price": 10.0, "free_quota": 0.1}, # 10元/GB/月 # 100MB免费
|
||||
"api_call": {"unit": "1000_calls", "price": 5.0, "free_quota": 1000}, # 5元/1000次 # 每月免费1000次
|
||||
"api_call": {
|
||||
"unit": "1000_calls",
|
||||
"price": 5.0,
|
||||
"free_quota": 1000,
|
||||
}, # 5元/1000次 # 每月免费1000次
|
||||
"export": {"unit": "page", "price": 0.1, "free_quota": 100}, # 0.1元/页(PDF导出)
|
||||
}
|
||||
|
||||
@@ -456,21 +483,39 @@ class SubscriptionManager:
|
||||
""")
|
||||
|
||||
# 创建索引
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_subscriptions_tenant ON subscriptions(tenant_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_subscriptions_status ON subscriptions(status)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_subscriptions_plan ON subscriptions(plan_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_usage_tenant ON usage_records(tenant_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_usage_type ON usage_records(resource_type)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_usage_recorded ON usage_records(recorded_at)")
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_subscriptions_tenant ON subscriptions(tenant_id)"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_subscriptions_status ON subscriptions(status)"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_subscriptions_plan ON subscriptions(plan_id)"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_usage_tenant ON usage_records(tenant_id)"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_usage_type ON usage_records(resource_type)"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_usage_recorded ON usage_records(recorded_at)"
|
||||
)
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_payments_tenant ON payments(tenant_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_payments_status ON payments(status)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_invoices_tenant ON invoices(tenant_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_invoices_status ON invoices(status)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_invoices_number ON invoices(invoice_number)")
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_invoices_number ON invoices(invoice_number)"
|
||||
)
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_refunds_tenant ON refunds(tenant_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_refunds_status ON refunds(status)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_billing_tenant ON billing_history(tenant_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_billing_created ON billing_history(created_at)")
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_tenant ON billing_history(tenant_id)"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_created ON billing_history(created_at)"
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
logger.info("Subscription tables initialized successfully")
|
||||
@@ -542,7 +587,9 @@ class SubscriptionManager:
|
||||
conn = self._get_connection()
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM subscription_plans WHERE tier = ? AND is_active = 1", (tier,))
|
||||
cursor.execute(
|
||||
"SELECT * FROM subscription_plans WHERE tier = ? AND is_active = 1", (tier,)
|
||||
)
|
||||
row = cursor.fetchone()
|
||||
|
||||
if row:
|
||||
@@ -561,7 +608,9 @@ class SubscriptionManager:
|
||||
if include_inactive:
|
||||
cursor.execute("SELECT * FROM subscription_plans ORDER BY price_monthly")
|
||||
else:
|
||||
cursor.execute("SELECT * FROM subscription_plans WHERE is_active = 1 ORDER BY price_monthly")
|
||||
cursor.execute(
|
||||
"SELECT * FROM subscription_plans WHERE is_active = 1 ORDER BY price_monthly"
|
||||
)
|
||||
|
||||
rows = cursor.fetchall()
|
||||
return [self._row_to_plan(row) for row in rows]
|
||||
@@ -679,7 +728,7 @@ class SubscriptionManager:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
f"""
|
||||
UPDATE subscription_plans SET {', '.join(updates)}
|
||||
UPDATE subscription_plans SET {", ".join(updates)}
|
||||
WHERE id = ?
|
||||
""",
|
||||
params,
|
||||
@@ -901,7 +950,7 @@ class SubscriptionManager:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
f"""
|
||||
UPDATE subscriptions SET {', '.join(updates)}
|
||||
UPDATE subscriptions SET {", ".join(updates)}
|
||||
WHERE id = ?
|
||||
""",
|
||||
params,
|
||||
@@ -913,7 +962,9 @@ class SubscriptionManager:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def cancel_subscription(self, subscription_id: str, at_period_end: bool = True) -> Subscription | None:
|
||||
def cancel_subscription(
|
||||
self, subscription_id: str, at_period_end: bool = True
|
||||
) -> Subscription | None:
|
||||
"""取消订阅"""
|
||||
conn = self._get_connection()
|
||||
try:
|
||||
@@ -965,7 +1016,9 @@ class SubscriptionManager:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def change_plan(self, subscription_id: str, new_plan_id: str, prorate: bool = True) -> Subscription | None:
|
||||
def change_plan(
|
||||
self, subscription_id: str, new_plan_id: str, prorate: bool = True
|
||||
) -> Subscription | None:
|
||||
"""更改订阅计划"""
|
||||
conn = self._get_connection()
|
||||
try:
|
||||
@@ -1214,7 +1267,9 @@ class SubscriptionManager:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def confirm_payment(self, payment_id: str, provider_payment_id: str | None = None) -> Payment | None:
|
||||
def confirm_payment(
|
||||
self, payment_id: str, provider_payment_id: str | None = None
|
||||
) -> Payment | None:
|
||||
"""确认支付完成"""
|
||||
conn = self._get_connection()
|
||||
try:
|
||||
@@ -1525,7 +1580,9 @@ class SubscriptionManager:
|
||||
|
||||
# ==================== 退款管理 ====================
|
||||
|
||||
def request_refund(self, tenant_id: str, payment_id: str, amount: float, reason: str, requested_by: str) -> Refund:
|
||||
def request_refund(
|
||||
self, tenant_id: str, payment_id: str, amount: float, reason: str, requested_by: str
|
||||
) -> Refund:
|
||||
"""申请退款"""
|
||||
conn = self._get_connection()
|
||||
try:
|
||||
@@ -1632,7 +1689,9 @@ class SubscriptionManager:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def complete_refund(self, refund_id: str, provider_refund_id: str | None = None) -> Refund | None:
|
||||
def complete_refund(
|
||||
self, refund_id: str, provider_refund_id: str | None = None
|
||||
) -> Refund | None:
|
||||
"""完成退款"""
|
||||
conn = self._get_connection()
|
||||
try:
|
||||
@@ -1825,7 +1884,12 @@ class SubscriptionManager:
|
||||
# ==================== 支付提供商集成 ====================
|
||||
|
||||
def create_stripe_checkout_session(
|
||||
self, tenant_id: str, plan_id: str, success_url: str, cancel_url: str, billing_cycle: str = "monthly"
|
||||
self,
|
||||
tenant_id: str,
|
||||
plan_id: str,
|
||||
success_url: str,
|
||||
cancel_url: str,
|
||||
billing_cycle: str = "monthly",
|
||||
) -> dict[str, Any]:
|
||||
"""创建 Stripe Checkout 会话(占位实现)"""
|
||||
# 这里应该集成 Stripe SDK
|
||||
@@ -1837,7 +1901,9 @@ class SubscriptionManager:
|
||||
"provider": "stripe",
|
||||
}
|
||||
|
||||
def create_alipay_order(self, tenant_id: str, plan_id: str, billing_cycle: str = "monthly") -> dict[str, Any]:
|
||||
def create_alipay_order(
|
||||
self, tenant_id: str, plan_id: str, billing_cycle: str = "monthly"
|
||||
) -> dict[str, Any]:
|
||||
"""创建支付宝订单(占位实现)"""
|
||||
# 这里应该集成支付宝 SDK
|
||||
plan = self.get_plan(plan_id)
|
||||
@@ -1852,7 +1918,9 @@ class SubscriptionManager:
|
||||
"provider": "alipay",
|
||||
}
|
||||
|
||||
def create_wechat_order(self, tenant_id: str, plan_id: str, billing_cycle: str = "monthly") -> dict[str, Any]:
|
||||
def create_wechat_order(
|
||||
self, tenant_id: str, plan_id: str, billing_cycle: str = "monthly"
|
||||
) -> dict[str, Any]:
|
||||
"""创建微信支付订单(占位实现)"""
|
||||
# 这里应该集成微信支付 SDK
|
||||
plan = self.get_plan(plan_id)
|
||||
@@ -1905,10 +1973,14 @@ class SubscriptionManager:
|
||||
limits=json.loads(row["limits"] or "{}"),
|
||||
is_active=bool(row["is_active"]),
|
||||
created_at=(
|
||||
datetime.fromisoformat(row["created_at"]) if isinstance(row["created_at"], str) else row["created_at"]
|
||||
datetime.fromisoformat(row["created_at"])
|
||||
if isinstance(row["created_at"], str)
|
||||
else row["created_at"]
|
||||
),
|
||||
updated_at=(
|
||||
datetime.fromisoformat(row["updated_at"]) if isinstance(row["updated_at"], str) else row["updated_at"]
|
||||
datetime.fromisoformat(row["updated_at"])
|
||||
if isinstance(row["updated_at"], str)
|
||||
else row["updated_at"]
|
||||
),
|
||||
metadata=json.loads(row["metadata"] or "{}"),
|
||||
)
|
||||
@@ -1949,10 +2021,14 @@ class SubscriptionManager:
|
||||
payment_provider=row["payment_provider"],
|
||||
provider_subscription_id=row["provider_subscription_id"],
|
||||
created_at=(
|
||||
datetime.fromisoformat(row["created_at"]) if isinstance(row["created_at"], str) else row["created_at"]
|
||||
datetime.fromisoformat(row["created_at"])
|
||||
if isinstance(row["created_at"], str)
|
||||
else row["created_at"]
|
||||
),
|
||||
updated_at=(
|
||||
datetime.fromisoformat(row["updated_at"]) if isinstance(row["updated_at"], str) else row["updated_at"]
|
||||
datetime.fromisoformat(row["updated_at"])
|
||||
if isinstance(row["updated_at"], str)
|
||||
else row["updated_at"]
|
||||
),
|
||||
metadata=json.loads(row["metadata"] or "{}"),
|
||||
)
|
||||
@@ -2001,10 +2077,14 @@ class SubscriptionManager:
|
||||
),
|
||||
failure_reason=row["failure_reason"],
|
||||
created_at=(
|
||||
datetime.fromisoformat(row["created_at"]) if isinstance(row["created_at"], str) else row["created_at"]
|
||||
datetime.fromisoformat(row["created_at"])
|
||||
if isinstance(row["created_at"], str)
|
||||
else row["created_at"]
|
||||
),
|
||||
updated_at=(
|
||||
datetime.fromisoformat(row["updated_at"]) if isinstance(row["updated_at"], str) else row["updated_at"]
|
||||
datetime.fromisoformat(row["updated_at"])
|
||||
if isinstance(row["updated_at"], str)
|
||||
else row["updated_at"]
|
||||
),
|
||||
)
|
||||
|
||||
@@ -2048,10 +2128,14 @@ class SubscriptionManager:
|
||||
),
|
||||
void_reason=row["void_reason"],
|
||||
created_at=(
|
||||
datetime.fromisoformat(row["created_at"]) if isinstance(row["created_at"], str) else row["created_at"]
|
||||
datetime.fromisoformat(row["created_at"])
|
||||
if isinstance(row["created_at"], str)
|
||||
else row["created_at"]
|
||||
),
|
||||
updated_at=(
|
||||
datetime.fromisoformat(row["updated_at"]) if isinstance(row["updated_at"], str) else row["updated_at"]
|
||||
datetime.fromisoformat(row["updated_at"])
|
||||
if isinstance(row["updated_at"], str)
|
||||
else row["updated_at"]
|
||||
),
|
||||
)
|
||||
|
||||
@@ -2086,10 +2170,14 @@ class SubscriptionManager:
|
||||
provider_refund_id=row["provider_refund_id"],
|
||||
metadata=json.loads(row["metadata"] or "{}"),
|
||||
created_at=(
|
||||
datetime.fromisoformat(row["created_at"]) if isinstance(row["created_at"], str) else row["created_at"]
|
||||
datetime.fromisoformat(row["created_at"])
|
||||
if isinstance(row["created_at"], str)
|
||||
else row["created_at"]
|
||||
),
|
||||
updated_at=(
|
||||
datetime.fromisoformat(row["updated_at"]) if isinstance(row["updated_at"], str) else row["updated_at"]
|
||||
datetime.fromisoformat(row["updated_at"])
|
||||
if isinstance(row["updated_at"], str)
|
||||
else row["updated_at"]
|
||||
),
|
||||
)
|
||||
|
||||
@@ -2105,14 +2193,18 @@ class SubscriptionManager:
|
||||
reference_id=row["reference_id"],
|
||||
balance_after=row["balance_after"],
|
||||
created_at=(
|
||||
datetime.fromisoformat(row["created_at"]) if isinstance(row["created_at"], str) else row["created_at"]
|
||||
datetime.fromisoformat(row["created_at"])
|
||||
if isinstance(row["created_at"], str)
|
||||
else row["created_at"]
|
||||
),
|
||||
metadata=json.loads(row["metadata"] or "{}"),
|
||||
)
|
||||
|
||||
|
||||
# 全局订阅管理器实例
|
||||
subscription_manager = None
|
||||
|
||||
|
||||
def get_subscription_manager(db_path: str = "insightflow.db") -> SubscriptionManager:
|
||||
"""获取订阅管理器实例(单例模式)"""
|
||||
global subscription_manager
|
||||
|
||||
Reference in New Issue
Block a user