feat: initialize aivideo project

This commit is contained in:
2026-04-17 18:33:05 +08:00
commit 14b18d67fe
162 changed files with 26251 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.models.entities import RechargeOrder
class PaymentsRepository:
def __init__(self, db: Session) -> None:
self.db = db
def get_order_by_id(self, order_id: int) -> RechargeOrder | None:
return self.db.scalar(select(RechargeOrder).where(RechargeOrder.id == order_id))
def list_orders(self):
return self.db.query(RechargeOrder).order_by(RechargeOrder.id.desc())

View File

@@ -0,0 +1,50 @@
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.common.db.session import get_db
from app.common.responses.api_response import success_response
from app.common.security.deps import require_admin_permission
from app.modules.payments.service import PaymentsService
from app.modules.wallets.service import WalletService
router = APIRouter(prefix="/api/v1/payments", tags=["payments"])
@router.post("/mock-notify")
def mock_notify(order_no: str, db: Session = Depends(get_db)):
return success_response(WalletService(db).handle_mock_payment(order_no))
@router.get("/mock-pay")
def mock_pay(orderNo: str, db: Session = Depends(get_db)):
return success_response(WalletService(db).handle_mock_payment(orderNo))
admin_router = APIRouter(prefix="/api/v1/admin/recharge-orders", tags=["admin-payments"])
@admin_router.get("")
def list_orders(
_=Depends(require_admin_permission()),
db: Session = Depends(get_db),
):
return success_response(PaymentsService(db).list_orders())
@admin_router.get("/{order_id}")
def get_order_detail(
order_id: int,
_=Depends(require_admin_permission()),
db: Session = Depends(get_db),
):
return success_response(PaymentsService(db).get_order_detail(order_id))
@admin_router.post("/{order_id}/repair")
def repair_order(
order_id: int,
_=Depends(require_admin_permission()),
db: Session = Depends(get_db),
):
return success_response(PaymentsService(db).repair_order(order_id))

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel, Field
class RepairOrderRequest(BaseModel):
remark: str = "manual repair"
class MockPaymentNotifyRequest(BaseModel):
order_no: str = Field(alias="orderNo")

View File

@@ -0,0 +1,42 @@
from sqlalchemy.orm import Session
from app.common.errors.app_error import NotFoundAppError
from app.modules.payments.repository import PaymentsRepository
from app.modules.wallets.service import WalletService
class PaymentsService:
def __init__(self, db: Session) -> None:
self.db = db
self.repository = PaymentsRepository(db)
self.wallet_service = WalletService(db)
def repair_order(self, order_id: int) -> dict:
order = self.repository.get_order_by_id(order_id)
if not order:
raise NotFoundAppError("order not found", code=30001)
return self.wallet_service.handle_mock_payment(order.order_no)
def list_orders(self) -> list[dict]:
rows = self.repository.list_orders().limit(200).all()
return [self.serialize_order(item) for item in rows]
def get_order_detail(self, order_id: int) -> dict:
order = self.repository.get_order_by_id(order_id)
if not order:
raise NotFoundAppError("order not found", code=30001)
return self.serialize_order(order)
@staticmethod
def serialize_order(order) -> dict:
return {
"id": order.id,
"orderNo": order.order_no,
"userId": order.user_id,
"payAmount": f"{order.pay_amount:.2f}",
"arrivalPoints": order.arrival_points,
"status": order.status,
"paymentChannelCode": order.payment_channel_code,
"paidAt": order.paid_at.isoformat() if order.paid_at else None,
"createdAt": order.created_at.isoformat(),
}