mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-23 13:13:09 +00:00
chore: 完成多批次代码优化与重构
- 重构工作流模块目录结构,迁移代码文件 - 修复类型断言空值安全问题,添加 ! 操作符 - 优化样式类名,替换 flex-cc 为标准 flex 工具类 - 更新路由标签简化文案,移除冗余注释 - 调整 ruff 配置,放宽行长度限制 - 更新 README 与多语言文案,优化项目描述 - 修复表单、图表组件的类型与样式问题 - 简化搜索表单、数据卡片的布局代码
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
"""订单与支付 Controller"""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Body, Depends, Path, Query, Request
|
||||
@@ -27,10 +28,10 @@ from .schema import (
|
||||
)
|
||||
from .service import OrderService, PaymentService, RefundService
|
||||
|
||||
OrderRouter = APIRouter(route_class=OperationLogRoute, prefix="/order", tags=["平台管理/订单管理"])
|
||||
PaymentRouter = APIRouter(route_class=OperationLogRoute, prefix="/payment", tags=["平台管理/支付管理"])
|
||||
RefundRouter = APIRouter(route_class=OperationLogRoute, prefix="/refund", tags=["平台管理/退款管理"])
|
||||
TenantOrderRouter = APIRouter(route_class=OperationLogRoute, prefix="/order", tags=["平台管理/租户订单"])
|
||||
OrderRouter = APIRouter(route_class=OperationLogRoute, prefix="/order", tags=["订单管理"])
|
||||
PaymentRouter = APIRouter(route_class=OperationLogRoute, prefix="/payment", tags=["支付管理"])
|
||||
RefundRouter = APIRouter(route_class=OperationLogRoute, prefix="/refund", tags=["退款管理"])
|
||||
TenantOrderRouter = APIRouter(route_class=OperationLogRoute, prefix="/order", tags=["租户订单"])
|
||||
|
||||
|
||||
def _make_bare_auth(db: AsyncSession) -> AuthSchema:
|
||||
@@ -44,7 +45,7 @@ def _make_bare_auth(db: AsyncSession) -> AuthSchema:
|
||||
@OrderRouter.post("/create", summary="创建订单", response_model=ResponseSchema[OrderOutSchema])
|
||||
async def order_create(
|
||||
data: Annotated[OrderCreateSchema, Body()],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:create']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:create"]))],
|
||||
) -> JSONResponse:
|
||||
"""
|
||||
创建订单
|
||||
@@ -62,7 +63,7 @@ async def order_create(
|
||||
@OrderRouter.get("/detail/{order_id}", summary="订单详情", response_model=ResponseSchema[OrderOutSchema])
|
||||
async def order_detail(
|
||||
order_id: Annotated[int, Path(ge=1)],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:query']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:query"]))],
|
||||
) -> JSONResponse:
|
||||
"""
|
||||
订单详情
|
||||
@@ -81,7 +82,7 @@ async def order_detail(
|
||||
|
||||
@OrderRouter.get("/list", summary="订单列表", response_model=ResponseSchema[PageResultSchema[OrderOutSchema]])
|
||||
async def order_list(
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:query']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:query"]))],
|
||||
tenant_id: Annotated[int | None, Query()] = None,
|
||||
status: Annotated[int | None, Query()] = None,
|
||||
order_type: Annotated[str | None, Query()] = None,
|
||||
@@ -117,7 +118,7 @@ async def order_list(
|
||||
@OrderRouter.post("/cancel/{order_id}", summary="取消订单", response_model=ResponseSchema[OrderStatusMessage])
|
||||
async def order_cancel(
|
||||
order_id: Annotated[int, Path(ge=1)],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:update']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:update"]))],
|
||||
) -> JSONResponse:
|
||||
"""
|
||||
取消订单
|
||||
@@ -131,13 +132,14 @@ async def order_cancel(
|
||||
result = await OrderService.cancel_order(auth, order_id)
|
||||
return SuccessResponse(data=result, msg=result["message"])
|
||||
|
||||
|
||||
# ─── 支付 ──────────────────────────────────────────────
|
||||
|
||||
|
||||
@PaymentRouter.post("/pay/{order_id}", summary="创建支付(获取支付 URL/二维码)", response_model=ResponseSchema[PaymentCreateOut])
|
||||
async def payment_create(
|
||||
order_id: Annotated[int, Path(ge=1)],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:update']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:update"]))],
|
||||
request: Request,
|
||||
method: Annotated[str, Query(description="支付渠道: alipay / wxpay(留空=自动)")] = "",
|
||||
) -> JSONResponse:
|
||||
@@ -160,6 +162,7 @@ async def payment_status(
|
||||
result = await OrderService.check_payment_status(auth, order_id)
|
||||
return SuccessResponse(data=result)
|
||||
|
||||
|
||||
# ─── 支付回调 ──────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -201,12 +204,13 @@ async def payment_mock_callback(
|
||||
logger.info(f"Mock 支付回调触发: order_id={order_id}")
|
||||
return SuccessResponse(data=result, msg="模拟支付成功")
|
||||
|
||||
|
||||
# ─── 支付记录 ──────────────────────────────────────────
|
||||
|
||||
|
||||
@PaymentRouter.get("/record/list", summary="支付记录列表", response_model=ResponseSchema[PageResultSchema[PaymentRecordOutSchema]])
|
||||
async def payment_record_list(
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:query']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:query"]))],
|
||||
page: Annotated[int, Query(ge=1)] = 1,
|
||||
page_size: Annotated[int, Query(ge=1, le=100)] = 20,
|
||||
) -> JSONResponse:
|
||||
@@ -231,12 +235,13 @@ async def payment_record_list(
|
||||
)
|
||||
return SuccessResponse(data=result)
|
||||
|
||||
|
||||
# ─── 退款管理 ──────────────────────────────────────────
|
||||
|
||||
|
||||
@RefundRouter.get("/list", summary="退款审核列表", response_model=ResponseSchema[PageResultSchema[RefundOutSchema]])
|
||||
async def refund_list(
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:query']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:query"]))],
|
||||
status: Annotated[int | None, Query(description="状态筛选")] = None,
|
||||
page: Annotated[int, Query(ge=1)] = 1,
|
||||
page_size: Annotated[int, Query(ge=1, le=100)] = 20,
|
||||
@@ -267,7 +272,7 @@ async def refund_list(
|
||||
@RefundRouter.put("/approve/{refund_id}", summary="批准退款", response_model=ResponseSchema[OrderStatusMessage])
|
||||
async def refund_approve(
|
||||
refund_id: Annotated[int, Path(ge=1)],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:update']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:update"]))],
|
||||
) -> JSONResponse:
|
||||
"""
|
||||
批准退款
|
||||
@@ -279,7 +284,8 @@ async def refund_approve(
|
||||
- JSONResponse: 包含批准结果的 JSON 响应。
|
||||
"""
|
||||
result = await RefundService.approve(
|
||||
auth, refund_id,
|
||||
auth,
|
||||
refund_id,
|
||||
auth.user.id if auth.user else 0,
|
||||
auth.user.name if auth.user else "",
|
||||
)
|
||||
@@ -290,7 +296,7 @@ async def refund_approve(
|
||||
async def refund_reject(
|
||||
refund_id: Annotated[int, Path(ge=1)],
|
||||
data: Annotated[RefundReviewSchema, Body()],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['module_platform:order:update']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_platform:order:update"]))],
|
||||
) -> JSONResponse:
|
||||
"""
|
||||
驳回退款
|
||||
@@ -303,19 +309,22 @@ async def refund_reject(
|
||||
- JSONResponse: 包含驳回结果的 JSON 响应。
|
||||
"""
|
||||
result = await RefundService.reject(
|
||||
auth, refund_id,
|
||||
auth.user.id if auth.user else 0, data,
|
||||
auth,
|
||||
refund_id,
|
||||
auth.user.id if auth.user else 0,
|
||||
data,
|
||||
auth.user.name if auth.user else "",
|
||||
)
|
||||
return SuccessResponse(data=result, msg=result["message"])
|
||||
|
||||
|
||||
# ─── 租户端订单 ────────────────────────────────────────
|
||||
|
||||
|
||||
@TenantOrderRouter.post("/create", summary="租户端创建订单", response_model=ResponseSchema[OrderOutSchema])
|
||||
async def tenant_order_create(
|
||||
data: Annotated[OrderCreateSchema, Body()],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['tenant:order:create']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["tenant:order:create"]))],
|
||||
) -> JSONResponse:
|
||||
"""
|
||||
租户端创建订单
|
||||
@@ -336,7 +345,7 @@ async def tenant_order_create(
|
||||
async def tenant_refund_apply(
|
||||
order_id: Annotated[int, Path(ge=1)],
|
||||
data: Annotated[RefundApplySchema, Body()],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(['tenant:order:refund']))],
|
||||
auth: Annotated[AuthSchema, Depends(AuthPermission(["tenant:order:refund"]))],
|
||||
) -> JSONResponse:
|
||||
"""
|
||||
租户端申请退款
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""订单与支付 CRUD"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
@@ -43,6 +44,7 @@ class OrderCRUD(CRUDBase[OrderModel, OrderCreateInternalSchema, OrderUpdateInter
|
||||
|
||||
async def mark_refunded(self, order_id: int) -> None:
|
||||
from sqlalchemy import update as sa_update
|
||||
|
||||
await self.db.execute(
|
||||
sa_update(OrderModel)
|
||||
.where(OrderModel.id == order_id)
|
||||
@@ -77,9 +79,7 @@ class PaymentRecordCRUD(CRUDBase[PaymentRecordModel, PaymentRecordCreateSchema,
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
super().__init__(model=PaymentRecordModel, auth=auth)
|
||||
|
||||
async def query(
|
||||
self, offset: int = 0, limit: int = 20
|
||||
) -> tuple[list[PaymentRecordModel], int]:
|
||||
async def query(self, offset: int = 0, limit: int = 20) -> tuple[list[PaymentRecordModel], int]:
|
||||
result = await self.page(
|
||||
order_by=[{"created_time": "desc"}],
|
||||
offset=offset,
|
||||
@@ -98,9 +98,7 @@ class RefundCRUD(CRUDBase[RefundModel, RefundCreateSchema, RefundUpdateSchema]):
|
||||
async def get_by_order_id(self, order_id: int) -> RefundModel | None:
|
||||
return await self.get(order_id=order_id)
|
||||
|
||||
async def query(
|
||||
self, status: int | None = None, offset: int = 0, limit: int = 20
|
||||
) -> tuple[list[RefundModel], int]:
|
||||
async def query(self, status: int | None = None, offset: int = 0, limit: int = 20) -> tuple[list[RefundModel], int]:
|
||||
result = await self.page(
|
||||
search={"status": status},
|
||||
order_by=[{"created_time": "desc"}],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""订单与支付 Model"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text
|
||||
@@ -29,6 +30,8 @@ class OrderModel(ModelMixin, TenantMixin):
|
||||
pay_method: Mapped[str | None] = mapped_column(String(20), nullable=True, comment="alipay/wxpay")
|
||||
pay_time: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, comment="支付时间")
|
||||
expire_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="订单过期时间(15分钟)")
|
||||
status: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="状态(0:启动 1:停用)", index=True)
|
||||
description: Mapped[str | None] = mapped_column(Text, default=None, nullable=True, comment="备注")
|
||||
|
||||
|
||||
class PaymentRecordModel(ModelMixin, TenantMixin):
|
||||
@@ -46,6 +49,8 @@ class PaymentRecordModel(ModelMixin, TenantMixin):
|
||||
amount: Mapped[int] = mapped_column(Integer, nullable=False, comment="支付金额(分)")
|
||||
raw_response: Mapped[str | None] = mapped_column(Text, nullable=True, comment="原始回调JSON")
|
||||
pay_time: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, comment="支付完成时间")
|
||||
status: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="状态(0:启动 1:停用)", index=True)
|
||||
description: Mapped[str | None] = mapped_column(Text, default=None, nullable=True, comment="备注")
|
||||
|
||||
|
||||
class RefundModel(ModelMixin, TenantMixin):
|
||||
@@ -65,3 +70,5 @@ class RefundModel(ModelMixin, TenantMixin):
|
||||
reviewer_id: Mapped[int | None] = mapped_column(ForeignKey("sys_user.id"), nullable=True, comment="审核人")
|
||||
review_time: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, comment="审核时间")
|
||||
reject_reason: Mapped[str | None] = mapped_column(Text, nullable=True, comment="驳回原因")
|
||||
status: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="状态(0:启动 1:停用)", index=True)
|
||||
description: Mapped[str | None] = mapped_column(Text, default=None, nullable=True, comment="备注")
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
"""订单与支付 Schema"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||
|
||||
from app.common.enums import QueueEnum
|
||||
from app.core.base_params import BaseQueryParam
|
||||
from app.core.base_schema import BaseSchema
|
||||
|
||||
# ─── Internal Create/Update Schemas(CRUD 层用,字段映射 Model 1:1)───
|
||||
@@ -12,6 +15,7 @@ from app.core.base_schema import BaseSchema
|
||||
|
||||
class OrderCreateInternalSchema(BaseModel):
|
||||
"""订单创建(内部 CRUD 用,包含所有业务字段)"""
|
||||
|
||||
order_no: str
|
||||
tenant_id: int
|
||||
package_id: int | None = None
|
||||
@@ -27,6 +31,7 @@ class OrderCreateInternalSchema(BaseModel):
|
||||
|
||||
class OrderUpdateInternalSchema(BaseModel):
|
||||
"""订单更新(内部 CRUD 用)"""
|
||||
|
||||
status: int | None = None
|
||||
pay_method: str | None = None
|
||||
pay_time: datetime | None = None
|
||||
@@ -34,6 +39,7 @@ class OrderUpdateInternalSchema(BaseModel):
|
||||
|
||||
class PaymentRecordCreateSchema(BaseModel):
|
||||
"""支付记录创建"""
|
||||
|
||||
order_id: int
|
||||
transaction_id: str | None = None
|
||||
pay_method: str
|
||||
@@ -45,6 +51,7 @@ class PaymentRecordCreateSchema(BaseModel):
|
||||
|
||||
class RefundCreateSchema(BaseModel):
|
||||
"""退款记录创建"""
|
||||
|
||||
order_id: int
|
||||
refund_no: str
|
||||
amount: int
|
||||
@@ -54,6 +61,7 @@ class RefundCreateSchema(BaseModel):
|
||||
|
||||
class RefundUpdateSchema(BaseModel):
|
||||
"""退款记录更新"""
|
||||
|
||||
status: int | None = None
|
||||
reviewer_id: int | None = None
|
||||
review_time: datetime | None = None
|
||||
@@ -65,6 +73,7 @@ class RefundUpdateSchema(BaseModel):
|
||||
|
||||
class OrderCreateSchema(BaseModel):
|
||||
"""创建订单(套餐或插件)"""
|
||||
|
||||
tenant_id: int
|
||||
package_id: int | None = Field(default=None, description="套餐ID(套餐订单必填)")
|
||||
plugin_id: int | None = Field(default=None, description="插件ID(插件订单必填)")
|
||||
@@ -91,6 +100,7 @@ class OrderCreateSchema(BaseModel):
|
||||
|
||||
class OrderOutSchema(BaseSchema):
|
||||
"""订单输出"""
|
||||
|
||||
order_no: str
|
||||
tenant_id: int
|
||||
package_id: int | None = None
|
||||
@@ -105,17 +115,32 @@ class OrderOutSchema(BaseSchema):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class OrderQueryParam(BaseModel):
|
||||
class OrderQueryParam(BaseQueryParam):
|
||||
"""订单查询参数"""
|
||||
tenant_id: int | None = None
|
||||
status: int | None = None
|
||||
order_type: str | None = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tenant_id: int | None = None,
|
||||
status: int | None = None,
|
||||
order_type: str | None = None,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
if tenant_id is not None:
|
||||
self.tenant_id = (QueueEnum.eq.value, tenant_id)
|
||||
if status is not None:
|
||||
self.status = (QueueEnum.eq.value, status)
|
||||
if order_type:
|
||||
self.order_type = (QueueEnum.eq.value, order_type)
|
||||
|
||||
|
||||
# ─── Payment ────────────────────────────────────────────
|
||||
|
||||
|
||||
class PaymentCallbackSchema(BaseModel):
|
||||
"""支付回调数据"""
|
||||
|
||||
transaction_id: str | None = None
|
||||
amount: int
|
||||
order_id: int | None = None
|
||||
@@ -124,6 +149,7 @@ class PaymentCallbackSchema(BaseModel):
|
||||
|
||||
class PaymentRecordOutSchema(BaseSchema):
|
||||
"""支付记录输出"""
|
||||
|
||||
order_id: int
|
||||
transaction_id: str | None = None
|
||||
pay_method: str
|
||||
@@ -135,6 +161,7 @@ class PaymentRecordOutSchema(BaseSchema):
|
||||
|
||||
class PaymentCreateOut(BaseModel):
|
||||
"""创建支付结果"""
|
||||
|
||||
pay_url: str
|
||||
qr_code_url: str
|
||||
trade_no: str
|
||||
@@ -145,6 +172,7 @@ class PaymentCreateOut(BaseModel):
|
||||
|
||||
class PaymentStatusOut(BaseModel):
|
||||
"""支付状态查询结果"""
|
||||
|
||||
exists: bool
|
||||
order_id: int | None = None
|
||||
status: int | None = None
|
||||
@@ -155,6 +183,7 @@ class PaymentStatusOut(BaseModel):
|
||||
|
||||
class OrderStatusMessage(BaseModel):
|
||||
"""订单/退款操作结果消息"""
|
||||
|
||||
id: int
|
||||
status: int
|
||||
message: str
|
||||
@@ -162,18 +191,22 @@ class OrderStatusMessage(BaseModel):
|
||||
|
||||
# ─── Refund ─────────────────────────────────────────────
|
||||
|
||||
|
||||
class RefundApplySchema(BaseModel):
|
||||
"""退款申请"""
|
||||
|
||||
reason: str = Field(min_length=1, max_length=500)
|
||||
|
||||
|
||||
class RefundReviewSchema(BaseModel):
|
||||
"""退款审核"""
|
||||
|
||||
reject_reason: str | None = Field(default=None, max_length=500)
|
||||
|
||||
|
||||
class RefundOutSchema(BaseSchema):
|
||||
"""退款记录输出"""
|
||||
|
||||
order_id: int
|
||||
refund_no: str
|
||||
amount: int
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""订单与支付 Service"""
|
||||
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
@@ -45,7 +46,6 @@ def _generate_refund_no() -> str:
|
||||
|
||||
|
||||
class OrderService:
|
||||
|
||||
@staticmethod
|
||||
async def create_order(auth: AuthSchema, data: OrderCreateSchema, amount: int | None = None) -> OrderOutSchema:
|
||||
"""创建订单
|
||||
@@ -56,10 +56,12 @@ class OrderService:
|
||||
if amount is None:
|
||||
if data.order_type == "plugin":
|
||||
from app.api.v1.module_platform.plugin.model import PluginModel
|
||||
|
||||
plugin = await auth.db.get(PluginModel, data.plugin_id)
|
||||
amount = plugin.price if plugin and hasattr(plugin, "price") else 0
|
||||
else:
|
||||
from app.api.v1.module_platform.package.model import PackageModel
|
||||
|
||||
pkg = await auth.db.get(PackageModel, data.package_id)
|
||||
amount = pkg.price if pkg and hasattr(pkg, "price") else 0
|
||||
|
||||
@@ -92,12 +94,13 @@ class OrderService:
|
||||
return OrderOutSchema.model_validate(order) if order else None
|
||||
|
||||
@staticmethod
|
||||
async def get_list(
|
||||
auth: AuthSchema, params: OrderQueryParam, offset: int, limit: int
|
||||
) -> tuple[list, int]:
|
||||
async def get_list(auth: AuthSchema, params: OrderQueryParam, offset: int, limit: int) -> tuple[list, int]:
|
||||
rows, total = await OrderCRUD(auth).query(
|
||||
tenant_id=params.tenant_id, status=params.status,
|
||||
order_type=params.order_type, offset=offset, limit=limit,
|
||||
tenant_id=params.tenant_id,
|
||||
status=params.status,
|
||||
order_type=params.order_type,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
)
|
||||
items = [OrderOutSchema.model_validate(r) for r in rows]
|
||||
return items, total
|
||||
@@ -135,11 +138,8 @@ class OrderService:
|
||||
|
||||
|
||||
class PaymentService:
|
||||
|
||||
@staticmethod
|
||||
async def create_payment(
|
||||
auth: AuthSchema, order_id: int, method: str, notify_base_url: str
|
||||
) -> PaymentCreateOut:
|
||||
async def create_payment(auth: AuthSchema, order_id: int, method: str, notify_base_url: str) -> PaymentCreateOut:
|
||||
"""创建支付(调用支付网关)"""
|
||||
from app.api.v1.module_platform.package.model import PackageModel
|
||||
|
||||
@@ -153,6 +153,7 @@ class PaymentService:
|
||||
|
||||
if order.order_type == "plugin":
|
||||
from app.api.v1.module_platform.plugin.model import PluginModel
|
||||
|
||||
plugin = await auth.db.get(PluginModel, order.plugin_id)
|
||||
subject = f"FastapiAdmin - 插件 {plugin.name}" if plugin else "FastapiAdmin 插件"
|
||||
else:
|
||||
@@ -178,9 +179,7 @@ class PaymentService:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def handle_callback(
|
||||
auth: AuthSchema, method: str, callback_data: dict
|
||||
) -> dict:
|
||||
async def handle_callback(auth: AuthSchema, method: str, callback_data: dict) -> dict:
|
||||
"""处理支付回调"""
|
||||
gateway = create_payment_gateway(method)
|
||||
callback_result = await gateway.verify_callback(callback_data)
|
||||
@@ -230,10 +229,7 @@ class PaymentService:
|
||||
order.order_type = otype
|
||||
await PaymentService._activate_tenant_package(auth, order)
|
||||
|
||||
logger.info(
|
||||
f"支付回调处理完成: order_id={oid} method={method} "
|
||||
f"tenant_id={tid} type={otype}"
|
||||
)
|
||||
logger.info(f"支付回调处理完成: order_id={oid} method={method} tenant_id={tid} type={otype}")
|
||||
return {"order_id": oid, "status": 1, "message": "支付成功"}
|
||||
|
||||
@staticmethod
|
||||
@@ -296,10 +292,12 @@ class PaymentService:
|
||||
return
|
||||
|
||||
result = await auth.db.execute(
|
||||
select(TenantPluginModel).where(
|
||||
select(TenantPluginModel)
|
||||
.where(
|
||||
TenantPluginModel.tenant_id == order.tenant_id,
|
||||
TenantPluginModel.plugin_id == order.plugin_id,
|
||||
).limit(1)
|
||||
)
|
||||
.limit(1)
|
||||
)
|
||||
existing = result.scalar_one_or_none()
|
||||
if existing:
|
||||
@@ -318,14 +316,13 @@ class PaymentService:
|
||||
logger.info(f"租户[{order.tenant_id}]已购买插件[{plugin.name}]")
|
||||
|
||||
from app.api.v1.module_platform.tenant.model import TenantModel
|
||||
|
||||
tenant = await auth.db.get(TenantModel, order.tenant_id)
|
||||
if tenant and tenant.contact_email:
|
||||
await PaymentService._send_order_email(order, plugin, tenant, order_type_label="购买")
|
||||
|
||||
@staticmethod
|
||||
async def _check_downgrade_quota(
|
||||
auth: AuthSchema, tenant_id: int, new_pkg: object
|
||||
) -> None:
|
||||
async def _check_downgrade_quota(auth: AuthSchema, tenant_id: int, new_pkg: object) -> None:
|
||||
"""降级前检查:租户当前资源数是否超过新套餐限额"""
|
||||
from sqlalchemy import func, select
|
||||
|
||||
@@ -342,21 +339,21 @@ class PaymentService:
|
||||
for label, (model, limit) in checks.items():
|
||||
if limit <= 0:
|
||||
continue
|
||||
count_stmt = select(func.count()).select_from(model).where(
|
||||
model.tenant_id == tenant_id,
|
||||
model.is_deleted.is_(False),
|
||||
count_stmt = (
|
||||
select(func.count())
|
||||
.select_from(model)
|
||||
.where(
|
||||
model.tenant_id == tenant_id,
|
||||
model.is_deleted.is_(False),
|
||||
)
|
||||
)
|
||||
result = await auth.db.execute(count_stmt)
|
||||
current = result.scalar() or 0
|
||||
if current > limit:
|
||||
raise CustomException(
|
||||
msg=f"降级失败:当前租户已有 {current} 个{label},超过目标套餐限额 {limit}"
|
||||
)
|
||||
raise CustomException(msg=f"降级失败:当前租户已有 {current} 个{label},超过目标套餐限额 {limit}")
|
||||
|
||||
@staticmethod
|
||||
async def _send_order_email(
|
||||
order: "OrderModel", product: object, tenant: object, order_type_label: str = ""
|
||||
) -> None:
|
||||
async def _send_order_email(order: "OrderModel", product: object, tenant: object, order_type_label: str = "") -> None:
|
||||
"""发送购买确认邮件(失败静默降级)"""
|
||||
try:
|
||||
from app.api.v1.module_platform.email.service import EmailSendService
|
||||
@@ -392,16 +389,13 @@ class PaymentService:
|
||||
pass # 邮件发送失败不阻塞业务流程
|
||||
|
||||
@staticmethod
|
||||
async def get_records(
|
||||
auth: AuthSchema, offset: int, limit: int
|
||||
) -> tuple[list, int]:
|
||||
async def get_records(auth: AuthSchema, offset: int, limit: int) -> tuple[list, int]:
|
||||
rows, total = await PaymentRecordCRUD(auth).query(offset, limit)
|
||||
items = [PaymentRecordOutSchema.model_validate(r) for r in rows]
|
||||
return items, total
|
||||
|
||||
|
||||
class RefundService:
|
||||
|
||||
@staticmethod
|
||||
async def apply(auth: AuthSchema, data: RefundApplySchema, order_id: int) -> RefundOutSchema:
|
||||
o_crud = OrderCRUD(auth)
|
||||
@@ -428,16 +422,13 @@ class RefundService:
|
||||
return RefundOutSchema.model_validate(refund)
|
||||
|
||||
@staticmethod
|
||||
async def get_list(
|
||||
auth: AuthSchema, status: int | None, offset: int, limit: int
|
||||
) -> tuple[list, int]:
|
||||
async def get_list(auth: AuthSchema, status: int | None, offset: int, limit: int) -> tuple[list, int]:
|
||||
rows, total = await RefundCRUD(auth).query(status, offset, limit)
|
||||
items = [RefundOutSchema.model_validate(r) for r in rows]
|
||||
return items, total
|
||||
|
||||
@staticmethod
|
||||
async def approve(auth: AuthSchema, refund_id: int, reviewer_id: int,
|
||||
operator_name: str = "") -> OrderStatusMessage:
|
||||
async def approve(auth: AuthSchema, refund_id: int, reviewer_id: int, operator_name: str = "") -> OrderStatusMessage:
|
||||
crud = RefundCRUD(auth)
|
||||
refund = await crud.get_by_id(refund_id)
|
||||
if not refund:
|
||||
@@ -453,8 +444,11 @@ class RefundService:
|
||||
|
||||
@staticmethod
|
||||
async def reject(
|
||||
auth: AuthSchema, refund_id: int, reviewer_id: int,
|
||||
data: RefundReviewSchema, operator_name: str = "",
|
||||
auth: AuthSchema,
|
||||
refund_id: int,
|
||||
reviewer_id: int,
|
||||
data: RefundReviewSchema,
|
||||
operator_name: str = "",
|
||||
) -> OrderStatusMessage:
|
||||
crud = RefundCRUD(auth)
|
||||
refund = await crud.get_by_id(refund_id)
|
||||
|
||||
Reference in New Issue
Block a user