123 lines
3.7 KiB
Python
123 lines
3.7 KiB
Python
import logging
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.config import settings
|
|
from app.models.payment_order import PaymentOrder
|
|
from app.services.credits import add_credits
|
|
from app.utils.id_gen import generate_id, generate_order_no
|
|
|
|
logger = logging.getLogger("videogen")
|
|
|
|
|
|
async def create_recharge_order(
|
|
db: AsyncSession,
|
|
user_id: str,
|
|
credits: float,
|
|
price: float,
|
|
label: str,
|
|
bonus_credits: float = 0.0,
|
|
method: str = "wechat",
|
|
) -> PaymentOrder:
|
|
"""Create a payment order. In mock mode, immediately completes payment."""
|
|
total_credits = credits + bonus_credits
|
|
order = PaymentOrder(
|
|
id=generate_id(),
|
|
user_id=user_id,
|
|
order_no=generate_order_no(),
|
|
amount=price,
|
|
credits=total_credits,
|
|
payment_method=method,
|
|
status="pending",
|
|
)
|
|
db.add(order)
|
|
await db.flush()
|
|
|
|
if settings.PAYMENT_MOCK:
|
|
# Mock: immediately complete payment
|
|
order.status = "paid"
|
|
order.paid_at = datetime.now()
|
|
desc = f"充值{label}({total_credits}积分)"
|
|
if bonus_credits > 0:
|
|
desc += f"(含赠送{bonus_credits}积分)"
|
|
await add_credits(
|
|
db,
|
|
user_id,
|
|
total_credits,
|
|
desc,
|
|
related_id=order.id,
|
|
)
|
|
await db.flush()
|
|
else:
|
|
# Real payment: delegate to WeChat or Alipay
|
|
if method == "wechat":
|
|
_create_wechat_order(order)
|
|
elif method == "alipay":
|
|
_create_alipay_order(order)
|
|
|
|
return order
|
|
|
|
|
|
def _create_wechat_order(order: PaymentOrder) -> None:
|
|
"""Create a WeChat Pay order. Stub for real integration."""
|
|
if not settings.WECHAT_MCH_ID or not settings.WECHAT_API_KEY:
|
|
logger.warning("WeChat payment config missing (WECHAT_MCH_ID / WECHAT_API_KEY)")
|
|
return
|
|
logger.info(
|
|
f"WeChat order created: mch_id={settings.WECHAT_MCH_ID}, "
|
|
f"order_no={order.order_no}, amount={order.amount}"
|
|
)
|
|
|
|
|
|
def _create_alipay_order(order: PaymentOrder) -> None:
|
|
"""Create an Alipay order. Stub for real integration."""
|
|
if not settings.ALIPAY_APP_ID or not settings.ALIPAY_PRIVATE_KEY:
|
|
logger.warning("Alipay payment config missing (ALIPAY_APP_ID / ALIPAY_PRIVATE_KEY)")
|
|
return
|
|
logger.info(
|
|
f"Alipay order created: app_id={settings.ALIPAY_APP_ID}, "
|
|
f"order_no={order.order_no}, amount={order.amount}"
|
|
)
|
|
|
|
|
|
async def verify_wechat_callback(data: dict) -> bool:
|
|
"""Verify WeChat payment callback signature."""
|
|
if settings.PAYMENT_MOCK:
|
|
return True
|
|
# Real verification would use WECHAT_API_KEY to verify signature
|
|
logger.info("WeChat callback verification (real mode not implemented)")
|
|
return True
|
|
|
|
|
|
async def verify_alipay_callback(data: dict) -> bool:
|
|
"""Verify Alipay payment callback signature."""
|
|
if settings.PAYMENT_MOCK:
|
|
return True
|
|
# Real verification would use ALIPAY_PUBLIC_KEY to verify signature
|
|
logger.info("Alipay callback verification (real mode not implemented)")
|
|
return True
|
|
|
|
|
|
async def process_payment_success(db: AsyncSession, order_id: str):
|
|
"""Process successful payment: update order and add credits."""
|
|
from sqlalchemy import select
|
|
|
|
result = await db.execute(
|
|
select(PaymentOrder).where(PaymentOrder.id == order_id)
|
|
)
|
|
order = result.scalar_one_or_none()
|
|
if not order or order.status != "pending":
|
|
return
|
|
|
|
order.status = "paid"
|
|
order.paid_at = datetime.now()
|
|
await add_credits(
|
|
db,
|
|
order.user_id,
|
|
order.credits,
|
|
f"充值成功({order.credits}积分)",
|
|
related_id=order.id,
|
|
)
|
|
await db.flush()
|