完成提现功能。
This commit is contained in:
parent
25c2936039
commit
6e37ea3bfe
214
app/api/endpoints/withdraw.py
Normal file
214
app/api/endpoints/withdraw.py
Normal file
@ -0,0 +1,214 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from app.models.withdraw import WithdrawDB, WithdrawCreate, WithdrawInfo, WithdrawStatus
|
||||
from app.models.user_bank_card import UserBankCardDB
|
||||
from app.models.user_account import UserAccountDB, AccountDetailDB, AccountDetailType
|
||||
from app.models.database import get_db
|
||||
from app.api.deps import get_current_user, get_admin_user
|
||||
from app.models.user import UserDB
|
||||
from app.core.response import success_response, error_response, ResponseModel
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional, Dict
|
||||
from datetime import datetime
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.post("", response_model=ResponseModel)
|
||||
async def create_withdraw(
|
||||
withdraw: WithdrawCreate,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: UserDB = Depends(get_current_user)
|
||||
):
|
||||
"""申请提现"""
|
||||
# 验证银行卡
|
||||
bank_card = db.query(UserBankCardDB).filter(
|
||||
UserBankCardDB.id == withdraw.bank_card_id,
|
||||
UserBankCardDB.user_id == current_user.userid
|
||||
).first()
|
||||
|
||||
if not bank_card:
|
||||
return error_response(code=404, message="银行卡不存在")
|
||||
|
||||
# 验证余额
|
||||
account = db.query(UserAccountDB).filter(
|
||||
UserAccountDB.user_id == current_user.userid
|
||||
).first()
|
||||
|
||||
if not account or account.balance < withdraw.amount:
|
||||
return error_response(code=400, message="余额不足")
|
||||
|
||||
try:
|
||||
# 创建提现记录
|
||||
withdraw_record = WithdrawDB(
|
||||
user_id=current_user.userid,
|
||||
bank_card_id=withdraw.bank_card_id,
|
||||
amount=withdraw.amount,
|
||||
status=WithdrawStatus.PENDING
|
||||
)
|
||||
db.add(withdraw_record)
|
||||
|
||||
# 更新账户余额
|
||||
account.balance -= Decimal(str(withdraw.amount))
|
||||
account.lock_balance += Decimal(str(withdraw.amount))
|
||||
|
||||
db.commit()
|
||||
db.refresh(withdraw_record)
|
||||
|
||||
return success_response(data=WithdrawInfo.model_validate(withdraw_record))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(code=500, message=f"申请提现失败: {str(e)}")
|
||||
|
||||
@router.post("/{withdraw_id}/approve", response_model=ResponseModel)
|
||||
async def approve_withdraw(
|
||||
withdraw_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
admin: UserDB = Depends(get_admin_user)
|
||||
):
|
||||
"""通过提现申请"""
|
||||
withdraw = db.query(WithdrawDB).filter(
|
||||
WithdrawDB.id == withdraw_id,
|
||||
WithdrawDB.status == WithdrawStatus.PENDING
|
||||
).first()
|
||||
|
||||
if not withdraw:
|
||||
return error_response(code=404, message="提现申请不存在或已处理")
|
||||
|
||||
try:
|
||||
# 更新提现状态
|
||||
withdraw.status = WithdrawStatus.APPROVED
|
||||
|
||||
# 更新账户余额
|
||||
account = db.query(UserAccountDB).filter(
|
||||
UserAccountDB.user_id == withdraw.user_id
|
||||
).first()
|
||||
|
||||
account.lock_balance -= withdraw.amount
|
||||
|
||||
# 添加账户明细记录
|
||||
detail = AccountDetailDB(
|
||||
user_id=withdraw.user_id,
|
||||
type=AccountDetailType.WITHDRAW,
|
||||
amount=withdraw.amount,
|
||||
balance=account.balance,
|
||||
description=f"提现到银行卡(尾号{withdraw.bank_card.card_number[-4:]})"
|
||||
)
|
||||
db.add(detail)
|
||||
|
||||
db.commit()
|
||||
return success_response(message="提现申请已通过")
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(code=500, message=f"处理失败: {str(e)}")
|
||||
|
||||
@router.post("/{withdraw_id}/reject", response_model=ResponseModel)
|
||||
async def reject_withdraw(
|
||||
withdraw_id: int,
|
||||
remark: str,
|
||||
db: Session = Depends(get_db),
|
||||
admin: UserDB = Depends(get_admin_user)
|
||||
):
|
||||
"""驳回提现申请"""
|
||||
withdraw = db.query(WithdrawDB).filter(
|
||||
WithdrawDB.id == withdraw_id,
|
||||
WithdrawDB.status == WithdrawStatus.PENDING
|
||||
).first()
|
||||
|
||||
if not withdraw:
|
||||
return error_response(code=404, message="提现申请不存在或已处理")
|
||||
|
||||
try:
|
||||
# 更新提现状态
|
||||
withdraw.status = WithdrawStatus.REJECTED
|
||||
withdraw.remark = remark
|
||||
|
||||
# 返还锁定余额
|
||||
account = db.query(UserAccountDB).filter(
|
||||
UserAccountDB.user_id == withdraw.user_id
|
||||
).first()
|
||||
|
||||
account.balance += withdraw.amount
|
||||
account.lock_balance -= withdraw.amount
|
||||
|
||||
db.commit()
|
||||
return success_response(message="提现申请已驳回")
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(code=500, message=f"处理失败: {str(e)}")
|
||||
|
||||
@router.get("/user", response_model=ResponseModel)
|
||||
async def get_user_withdraws(
|
||||
status: Optional[WithdrawStatus] = None,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: UserDB = Depends(get_current_user)
|
||||
):
|
||||
"""获取提现记录列表"""
|
||||
query = db.query(WithdrawDB).filter(WithdrawDB.user_id == current_user.userid)
|
||||
|
||||
if status:
|
||||
query = query.filter(WithdrawDB.status == status)
|
||||
|
||||
withdraws = query.order_by(WithdrawDB.create_time.desc()).all()
|
||||
|
||||
return success_response(data=[WithdrawInfo.model_validate(w) for w in withdraws])
|
||||
|
||||
@router.get("", response_model=ResponseModel)
|
||||
async def get_all_withdraws(
|
||||
status: Optional[WithdrawStatus] = None,
|
||||
start_time: Optional[datetime] = None,
|
||||
end_time: Optional[datetime] = None,
|
||||
skip: int = 0,
|
||||
limit: int = 20,
|
||||
db: Session = Depends(get_db),
|
||||
admin: UserDB = Depends(get_admin_user)
|
||||
):
|
||||
"""
|
||||
管理员获取所有提现记录
|
||||
|
||||
Args:
|
||||
status: 提现状态筛选
|
||||
start_time: 开始时间
|
||||
end_time: 结束时间
|
||||
skip: 跳过记录数
|
||||
limit: 返回记录数
|
||||
"""
|
||||
# 构建查询
|
||||
query = db.query(WithdrawDB).join(
|
||||
UserBankCardDB,
|
||||
WithdrawDB.bank_card_id == UserBankCardDB.id
|
||||
)
|
||||
|
||||
# 应用筛选条件
|
||||
if status:
|
||||
query = query.filter(WithdrawDB.status == status)
|
||||
if start_time:
|
||||
query = query.filter(WithdrawDB.create_time >= start_time)
|
||||
if end_time:
|
||||
query = query.filter(WithdrawDB.create_time <= end_time)
|
||||
|
||||
# 计算总数
|
||||
total = query.count()
|
||||
|
||||
# 分页
|
||||
withdraws = query.order_by(WithdrawDB.create_time.desc())\
|
||||
.offset(skip)\
|
||||
.limit(limit)\
|
||||
.all()
|
||||
|
||||
# 构建返回数据
|
||||
withdraw_list = []
|
||||
for w in withdraws:
|
||||
withdraw_info = WithdrawInfo.model_validate(w)
|
||||
# 添加额外信息
|
||||
withdraw_info_dict = withdraw_info.model_dump()
|
||||
withdraw_info_dict.update({
|
||||
"bank_card_number": w.bank_card.card_number, # 银行卡号
|
||||
"bank_name": w.bank_card.bank_name, # 银行名称
|
||||
"name": w.bank_card.name # 持卡人姓名
|
||||
})
|
||||
withdraw_list.append(withdraw_info_dict)
|
||||
|
||||
return success_response(data={
|
||||
"items": withdraw_list,
|
||||
"total": total
|
||||
})
|
||||
@ -1,6 +1,6 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from app.api.endpoints import wechat,user, address, community, station, order, coupon, community_building, upload, merchant, merchant_product, merchant_order, point, config, merchant_category, log, account,merchant_pay_order, message, bank_card
|
||||
from app.api.endpoints import wechat,user, address, community, station, order, coupon, community_building, upload, merchant, merchant_product, merchant_order, point, config, merchant_category, log, account,merchant_pay_order, message, bank_card, withdraw
|
||||
from app.models.database import Base, engine
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
@ -33,6 +33,7 @@ app.add_middleware(RequestLoggerMiddleware)
|
||||
app.include_router(wechat.router,prefix="/api/wechat",tags=["微信"])
|
||||
app.include_router(user.router, prefix="/api/user", tags=["用户"])
|
||||
app.include_router(bank_card.router, prefix="/api/bank-cards", tags=["用户银行卡"])
|
||||
app.include_router(withdraw.router, prefix="/api/withdraw", tags=["提现"])
|
||||
app.include_router(point.router, prefix="/api/point", tags=["用户积分"])
|
||||
app.include_router(account.router, prefix="/api/account", tags=["账户"])
|
||||
app.include_router(address.router, prefix="/api/address", tags=["配送地址"])
|
||||
|
||||
@ -17,6 +17,7 @@ class UserAccountDB(Base):
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id = Column(Integer, ForeignKey("users.userid"), unique=True, nullable=False)
|
||||
balance = Column(DECIMAL(10, 2), nullable=False, default=0)
|
||||
lock_balance = Column(DECIMAL(10, 2), nullable=False, default=0)
|
||||
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
|
||||
43
app/models/withdraw.py
Normal file
43
app/models/withdraw.py
Normal file
@ -0,0 +1,43 @@
|
||||
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey, Enum, DECIMAL
|
||||
from sqlalchemy.sql import func
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
from .database import Base
|
||||
import enum
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
class WithdrawStatus(str, enum.Enum):
|
||||
PENDING = "PENDING" # 已申请
|
||||
APPROVED = "APPROVED" # 已通过
|
||||
REJECTED = "REJECTED" # 已驳回
|
||||
|
||||
class WithdrawDB(Base):
|
||||
__tablename__ = "withdraws"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id = Column(Integer, ForeignKey("users.userid"), nullable=False)
|
||||
bank_card_id = Column(Integer, ForeignKey("user_bank_cards.id"), nullable=False)
|
||||
amount = Column(DECIMAL(10, 2), nullable=False)
|
||||
status = Column(Enum(WithdrawStatus), nullable=False, default=WithdrawStatus.PENDING)
|
||||
remark = Column(String(200)) # 备注(驳回原因等)
|
||||
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
# 关联关系
|
||||
bank_card = relationship("UserBankCardDB", backref="withdraws")
|
||||
|
||||
class WithdrawCreate(BaseModel):
|
||||
bank_card_id: int
|
||||
amount: float = Field(..., gt=0)
|
||||
|
||||
class WithdrawInfo(BaseModel):
|
||||
id: int
|
||||
bank_card_id: int
|
||||
amount: float
|
||||
status: WithdrawStatus
|
||||
remark: Optional[str]
|
||||
create_time: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
Loading…
Reference in New Issue
Block a user