Spaces:
Running
Running
Upload 4 files
Browse files- database_sql.py +16 -2
- models_sql.py +1 -0
- router_tasks.py +4 -4
- router_wallet.py +20 -2
database_sql.py
CHANGED
|
@@ -141,7 +141,21 @@ def _auto_migrate_p7_fields():
|
|
| 141 |
|
| 142 |
conn.commit()
|
| 143 |
|
| 144 |
-
# ========== 2. 迁移
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
if 'transactions' in inspector.get_table_names():
|
| 146 |
columns = [col['name'] for col in inspector.get_columns('transactions')]
|
| 147 |
|
|
@@ -170,7 +184,7 @@ def _auto_migrate_p7_fields():
|
|
| 170 |
|
| 171 |
conn.commit()
|
| 172 |
|
| 173 |
-
# ==========
|
| 174 |
# 将旧 WITHDRAW 记录的 withdraw_status 从 NULL 更新为 "completed"
|
| 175 |
result = conn.execute(text(
|
| 176 |
"UPDATE transactions SET withdraw_status = 'completed' "
|
|
|
|
| 141 |
|
| 142 |
conn.commit()
|
| 143 |
|
| 144 |
+
# ========== 2. 迁移 wallets 表(新增 task_balance 字段) ==========
|
| 145 |
+
if 'wallets' in inspector.get_table_names():
|
| 146 |
+
columns = [col['name'] for col in inspector.get_columns('wallets')]
|
| 147 |
+
|
| 148 |
+
with engine.connect() as conn:
|
| 149 |
+
if 'task_balance' not in columns:
|
| 150 |
+
if 'sqlite' in SQLALCHEMY_DATABASE_URL:
|
| 151 |
+
conn.execute(text("ALTER TABLE wallets ADD COLUMN task_balance INTEGER DEFAULT 0"))
|
| 152 |
+
else:
|
| 153 |
+
conn.execute(text("ALTER TABLE wallets ADD COLUMN task_balance INTEGER DEFAULT 0"))
|
| 154 |
+
logger.info("[DB Migration] 添加列 wallets.task_balance")
|
| 155 |
+
|
| 156 |
+
conn.commit()
|
| 157 |
+
|
| 158 |
+
# ========== 3. 迁移 transactions 表(提现相关新字段) ==========
|
| 159 |
if 'transactions' in inspector.get_table_names():
|
| 160 |
columns = [col['name'] for col in inspector.get_columns('transactions')]
|
| 161 |
|
|
|
|
| 184 |
|
| 185 |
conn.commit()
|
| 186 |
|
| 187 |
+
# ========== 4. 回填旧提现记录数据 ==========
|
| 188 |
# 将旧 WITHDRAW 记录的 withdraw_status 从 NULL 更新为 "completed"
|
| 189 |
result = conn.execute(text(
|
| 190 |
"UPDATE transactions SET withdraw_status = 'completed' "
|
models_sql.py
CHANGED
|
@@ -19,6 +19,7 @@ class Wallet(Base):
|
|
| 19 |
balance = Column(Integer, default=0, nullable=False) # 用于消费的余额 (充值获得)
|
| 20 |
earn_balance = Column(Integer, default=0, nullable=False) # 创作者销售收益余额 (别人购买获得)
|
| 21 |
tip_balance = Column(Integer, default=0, nullable=False) # 【新增】创作者打赏收益余额 (粉丝赞助获得)
|
|
|
|
| 22 |
frozen_balance = Column(Integer, default=0, nullable=False) # 提现审核冻结中的余额
|
| 23 |
|
| 24 |
# 乐观锁版本号,防止并发扣款被击穿
|
|
|
|
| 19 |
balance = Column(Integer, default=0, nullable=False) # 用于消费的余额 (充值获得)
|
| 20 |
earn_balance = Column(Integer, default=0, nullable=False) # 创作者销售收益余额 (别人购买获得)
|
| 21 |
tip_balance = Column(Integer, default=0, nullable=False) # 【新增】创作者打赏收益余额 (粉丝赞助获得)
|
| 22 |
+
task_balance = Column(Integer, default=0, nullable=False) # 【新增】任务相关余额
|
| 23 |
frozen_balance = Column(Integer, default=0, nullable=False) # 提现审核冻结中的余额
|
| 24 |
|
| 25 |
# 乐观锁版本号,防止并发扣款被击穿
|
router_tasks.py
CHANGED
|
@@ -806,7 +806,7 @@ async def accept_task(task_id: str, is_accepted: bool, feedback: str = None, cur
|
|
| 806 |
db_session.flush()
|
| 807 |
|
| 808 |
assignee_wallet.balance += total_price # 全款进入可用余额
|
| 809 |
-
assignee_wallet.
|
| 810 |
|
| 811 |
# 获取双方用户名
|
| 812 |
users_db = db.load_data("users.json", default_data={})
|
|
@@ -1159,7 +1159,7 @@ async def resolve_dispute(dispute_id: str, resolution: str, ratio: int = None, n
|
|
| 1159 |
publisher_wallet.frozen_balance = max(0, publisher_wallet.frozen_balance - remaining)
|
| 1160 |
# 接单者获得全款
|
| 1161 |
assignee_wallet.balance += total_price
|
| 1162 |
-
assignee_wallet.
|
| 1163 |
|
| 1164 |
# 记录交易
|
| 1165 |
create_task_transaction(
|
|
@@ -1186,7 +1186,7 @@ async def resolve_dispute(dispute_id: str, resolution: str, ratio: int = None, n
|
|
| 1186 |
publisher_wallet.frozen_balance = max(0, publisher_wallet.frozen_balance - remaining)
|
| 1187 |
# 接单者获得全款
|
| 1188 |
assignee_wallet.balance += total_price
|
| 1189 |
-
assignee_wallet.
|
| 1190 |
|
| 1191 |
# 记录交易
|
| 1192 |
create_task_transaction(
|
|
@@ -1240,7 +1240,7 @@ async def resolve_dispute(dispute_id: str, resolution: str, ratio: int = None, n
|
|
| 1240 |
# 分配资金
|
| 1241 |
publisher_wallet.balance += pub_refund
|
| 1242 |
assignee_wallet.balance += assignee_earn
|
| 1243 |
-
assignee_wallet.
|
| 1244 |
|
| 1245 |
# 记录交易
|
| 1246 |
create_task_transaction(
|
|
|
|
| 806 |
db_session.flush()
|
| 807 |
|
| 808 |
assignee_wallet.balance += total_price # 全款进入可用余额
|
| 809 |
+
assignee_wallet.task_balance += total_price # 累计任务收益统计(只增不减)
|
| 810 |
|
| 811 |
# 获取双方用户名
|
| 812 |
users_db = db.load_data("users.json", default_data={})
|
|
|
|
| 1159 |
publisher_wallet.frozen_balance = max(0, publisher_wallet.frozen_balance - remaining)
|
| 1160 |
# 接单者获得全款
|
| 1161 |
assignee_wallet.balance += total_price
|
| 1162 |
+
assignee_wallet.task_balance += total_price
|
| 1163 |
|
| 1164 |
# 记录交易
|
| 1165 |
create_task_transaction(
|
|
|
|
| 1186 |
publisher_wallet.frozen_balance = max(0, publisher_wallet.frozen_balance - remaining)
|
| 1187 |
# 接单者获得全款
|
| 1188 |
assignee_wallet.balance += total_price
|
| 1189 |
+
assignee_wallet.task_balance += total_price
|
| 1190 |
|
| 1191 |
# 记录交易
|
| 1192 |
create_task_transaction(
|
|
|
|
| 1240 |
# 分配资金
|
| 1241 |
publisher_wallet.balance += pub_refund
|
| 1242 |
assignee_wallet.balance += assignee_earn
|
| 1243 |
+
assignee_wallet.task_balance += assignee_earn
|
| 1244 |
|
| 1245 |
# 记录交易
|
| 1246 |
create_task_transaction(
|
router_wallet.py
CHANGED
|
@@ -37,6 +37,9 @@ REFUND_WINDOW_HOURS = 24
|
|
| 37 |
# 🔄 P7后悔模式:退款后30天禁购
|
| 38 |
REFUND_BAN_DAYS = 30
|
| 39 |
|
|
|
|
|
|
|
|
|
|
| 40 |
# 📝 P2优化:审计日志
|
| 41 |
logger = logging.getLogger("ComfyUI-Ranking.Wallet")
|
| 42 |
|
|
@@ -253,13 +256,14 @@ async def get_wallet(account: str, db: Session = Depends(get_db)):
|
|
| 253 |
total_withdrawn = abs(total_withdrawn) # 提现金额是负数
|
| 254 |
|
| 255 |
if not wallet:
|
| 256 |
-
return {"status": "success", "balance": 0, "earn_balance": 0, "tip_balance": 0, "frozen_balance": 0, "total_withdrawn": total_withdrawn}
|
| 257 |
|
| 258 |
return {
|
| 259 |
"status": "success",
|
| 260 |
"balance": wallet.balance,
|
| 261 |
"earn_balance": wallet.earn_balance,
|
| 262 |
"tip_balance": wallet.tip_balance,
|
|
|
|
| 263 |
"frozen_balance": wallet.frozen_balance,
|
| 264 |
"total_withdrawn": total_withdrawn # 暴露给前端
|
| 265 |
}
|
|
@@ -624,6 +628,15 @@ async def withdraw(request: Request, req: WithdrawRequest, db: Session = Depends
|
|
| 624 |
wallet.balance -= actual_withdraw # 直接从统一余额扣除
|
| 625 |
wallet.frozen_balance += net_amount # 冻结的是到账金额,非手续费部分
|
| 626 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 627 |
tx_id = f"WD_{int(time.time())}_{uuid.uuid4().hex[:6]}"
|
| 628 |
last_tx = db.query(Transaction).filter(Transaction.account == req.account).order_by(Transaction.created_at.desc()).first()
|
| 629 |
prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
|
|
@@ -917,7 +930,12 @@ async def refund_purchase(request: Request, account: str, item_id: str, db: Sess
|
|
| 917 |
|
| 918 |
if seller_wallet:
|
| 919 |
seller_wallet.balance -= refund_amount # 卖家扣回
|
| 920 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 921 |
|
| 922 |
if buyer_wallet:
|
| 923 |
buyer_wallet.balance += refund_amount # 买家退款
|
|
|
|
| 37 |
# 🔄 P7后悔模式:退款后30天禁购
|
| 38 |
REFUND_BAN_DAYS = 30
|
| 39 |
|
| 40 |
+
# 💰 系统手续费账户
|
| 41 |
+
SYSTEM_FEE_ACCOUNT = "system_fee_account"
|
| 42 |
+
|
| 43 |
# 📝 P2优化:审计日志
|
| 44 |
logger = logging.getLogger("ComfyUI-Ranking.Wallet")
|
| 45 |
|
|
|
|
| 256 |
total_withdrawn = abs(total_withdrawn) # 提现金额是负数
|
| 257 |
|
| 258 |
if not wallet:
|
| 259 |
+
return {"status": "success", "balance": 0, "earn_balance": 0, "tip_balance": 0, "task_balance": 0, "frozen_balance": 0, "total_withdrawn": total_withdrawn}
|
| 260 |
|
| 261 |
return {
|
| 262 |
"status": "success",
|
| 263 |
"balance": wallet.balance,
|
| 264 |
"earn_balance": wallet.earn_balance,
|
| 265 |
"tip_balance": wallet.tip_balance,
|
| 266 |
+
"task_balance": wallet.task_balance or 0,
|
| 267 |
"frozen_balance": wallet.frozen_balance,
|
| 268 |
"total_withdrawn": total_withdrawn # 暴露给前端
|
| 269 |
}
|
|
|
|
| 628 |
wallet.balance -= actual_withdraw # 直接从统一余额扣除
|
| 629 |
wallet.frozen_balance += net_amount # 冻结的是到账金额,非手续费部分
|
| 630 |
|
| 631 |
+
# 💰 手续费转入系统账户
|
| 632 |
+
if fee_amount > 0:
|
| 633 |
+
sys_wallet = db.query(Wallet).filter(Wallet.account == SYSTEM_FEE_ACCOUNT).with_for_update().first()
|
| 634 |
+
if not sys_wallet:
|
| 635 |
+
sys_wallet = Wallet(account=SYSTEM_FEE_ACCOUNT, balance=0, earn_balance=0, tip_balance=0, task_balance=0, frozen_balance=0)
|
| 636 |
+
db.add(sys_wallet)
|
| 637 |
+
db.flush()
|
| 638 |
+
sys_wallet.balance += fee_amount
|
| 639 |
+
|
| 640 |
tx_id = f"WD_{int(time.time())}_{uuid.uuid4().hex[:6]}"
|
| 641 |
last_tx = db.query(Transaction).filter(Transaction.account == req.account).order_by(Transaction.created_at.desc()).first()
|
| 642 |
prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
|
|
|
|
| 930 |
|
| 931 |
if seller_wallet:
|
| 932 |
seller_wallet.balance -= refund_amount # 卖家扣回
|
| 933 |
+
# 不修改 earn_balance(保持"累计销售收益只增不减"语义)
|
| 934 |
+
|
| 935 |
+
# P1 退款负数保护
|
| 936 |
+
if seller_wallet.balance < 0:
|
| 937 |
+
db.rollback()
|
| 938 |
+
raise HTTPException(status_code=400, detail="卖家余额不足,无法处理退款")
|
| 939 |
|
| 940 |
if buyer_wallet:
|
| 941 |
buyer_wallet.balance += refund_amount # 买家退款
|