Spaces:
Running
Running
增加更多详细交易数据
Browse files- database_sql.py +4 -0
- models_sql.py +6 -0
- router_tasks.py +47 -8
- router_wallet.py +91 -15
database_sql.py
CHANGED
|
@@ -153,6 +153,10 @@ def _auto_migrate_p7_fields():
|
|
| 153 |
'withdraw_status': 'VARCHAR',
|
| 154 |
'payment_order_id': 'VARCHAR',
|
| 155 |
'net_amount': 'INTEGER',
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
}
|
| 157 |
|
| 158 |
for col_name, col_type in new_columns.items():
|
|
|
|
| 153 |
'withdraw_status': 'VARCHAR',
|
| 154 |
'payment_order_id': 'VARCHAR',
|
| 155 |
'net_amount': 'INTEGER',
|
| 156 |
+
'description': 'VARCHAR',
|
| 157 |
+
'item_title': 'VARCHAR',
|
| 158 |
+
'item_type': 'VARCHAR',
|
| 159 |
+
'related_user_name': 'VARCHAR',
|
| 160 |
}
|
| 161 |
|
| 162 |
for col_name, col_type in new_columns.items():
|
models_sql.py
CHANGED
|
@@ -75,6 +75,12 @@ class Transaction(Base):
|
|
| 75 |
payment_order_id = Column(String, nullable=True) # 管理员填写的打款订单号
|
| 76 |
net_amount = Column(Integer, nullable=True) # 实际到账金额(用于解冻时准确扣减)
|
| 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
# 🚀 P1性能优化:复合索引
|
| 79 |
__table_args__ = (
|
| 80 |
Index('ix_transactions_account_type', 'account', 'tx_type'),
|
|
|
|
| 75 |
payment_order_id = Column(String, nullable=True) # 管理员填写的打款订单号
|
| 76 |
net_amount = Column(Integer, nullable=True) # 实际到账金额(用于解冻时准确扣减)
|
| 77 |
|
| 78 |
+
# 交易详情增强字段
|
| 79 |
+
description = Column(String, nullable=True) # 交易自描述文本
|
| 80 |
+
item_title = Column(String, nullable=True) # 资源/任务标题
|
| 81 |
+
item_type = Column(String, nullable=True) # 资源类型 (tool/app/recommend/post/task)
|
| 82 |
+
related_user_name = Column(String, nullable=True) # 对方用户名
|
| 83 |
+
|
| 84 |
# 🚀 P1性能优化:复合索引
|
| 85 |
__table_args__ = (
|
| 86 |
Index('ix_transactions_account_type', 'account', 'tx_type'),
|
router_tasks.py
CHANGED
|
@@ -37,7 +37,9 @@ def calculate_tx_hash(tx_id, account, tx_type, amount, prev_hash):
|
|
| 37 |
data = f"{tx_id}{account}{tx_type}{amount}{prev_hash}"
|
| 38 |
return hashlib.sha256(data.encode()).hexdigest()
|
| 39 |
|
| 40 |
-
def create_task_transaction(db_session: Session, account: str, tx_type: str, amount: int,
|
|
|
|
|
|
|
| 41 |
"""
|
| 42 |
创建任务相关交易记录
|
| 43 |
tx_type: TASK_FREEZE, TASK_DEPOSIT, TASK_PAYMENT, TASK_INCOME, TASK_REFUND
|
|
@@ -48,6 +50,18 @@ def create_task_transaction(db_session: Session, account: str, tx_type: str, amo
|
|
| 48 |
prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
|
| 49 |
tx_hash = calculate_tx_hash(tx_id, account, tx_type, amount, prev_hash)
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
new_tx = Transaction(
|
| 52 |
tx_id=tx_id,
|
| 53 |
account=account,
|
|
@@ -56,7 +70,11 @@ def create_task_transaction(db_session: Session, account: str, tx_type: str, amo
|
|
| 56 |
related_account=related_account,
|
| 57 |
item_id=task_id, # 复用 item_id 字段存储任务ID
|
| 58 |
prev_hash=prev_hash,
|
| 59 |
-
tx_hash=tx_hash
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
)
|
| 61 |
db_session.add(new_tx)
|
| 62 |
|
|
@@ -152,7 +170,8 @@ def check_and_update_expired_tasks(tasks_db, db_session=None):
|
|
| 152 |
# 记录退款交易
|
| 153 |
create_task_transaction(
|
| 154 |
db_session, item["publisher"], "TASK_REFUND",
|
| 155 |
-
item["amount"], task_id=item["task_id"]
|
|
|
|
| 156 |
)
|
| 157 |
|
| 158 |
refund_results.append(item)
|
|
@@ -411,7 +430,8 @@ async def create_task(task: TaskCreate, current_user: str = Depends(require_auth
|
|
| 411 |
# 💳 记录冻结交易
|
| 412 |
create_task_transaction(
|
| 413 |
db_session, current_user, "TASK_FREEZE",
|
| 414 |
-
-task.totalPrice, task_id=task_id
|
|
|
|
| 415 |
)
|
| 416 |
db_session.commit()
|
| 417 |
|
|
@@ -518,7 +538,8 @@ async def cancel_task(task_id: str, current_user: str = Depends(require_auth), d
|
|
| 518 |
# 记录退款交易
|
| 519 |
create_task_transaction(
|
| 520 |
db_session, current_user, "TASK_CANCEL_REFUND",
|
| 521 |
-
frozen_amount, task_id=task_id
|
|
|
|
| 522 |
)
|
| 523 |
db_session.commit()
|
| 524 |
refund_success = True
|
|
@@ -654,10 +675,17 @@ async def assign_task(task_id: str, assignee: str, current_user: str = Depends(r
|
|
| 654 |
# 订金从冻结金额中扣除(但还不给接单者,待任务完成后一起支付)
|
| 655 |
wallet.frozen_balance -= deposit
|
| 656 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 657 |
# 💳 记录订金支付交易
|
| 658 |
create_task_transaction(
|
| 659 |
db_session, current_user, "TASK_DEPOSIT",
|
| 660 |
-
-deposit, related_account=assignee, task_id=task_id
|
|
|
|
|
|
|
| 661 |
)
|
| 662 |
|
| 663 |
# 更新任务状态
|
|
@@ -779,16 +807,27 @@ async def accept_task(task_id: str, is_accepted: bool, feedback: str = None, cur
|
|
| 779 |
|
| 780 |
assignee_wallet.balance += total_price # 全款进入可用余额
|
| 781 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 782 |
# 💳 记录交易流水
|
| 783 |
# 1. 发布者支付尾款
|
| 784 |
create_task_transaction(
|
| 785 |
db_session, current_user, "TASK_PAYMENT",
|
| 786 |
-
-remaining, related_account=assignee_account, task_id=task_id
|
|
|
|
|
|
|
| 787 |
)
|
| 788 |
# 2. 接单者收入
|
| 789 |
create_task_transaction(
|
| 790 |
db_session, assignee_account, "TASK_INCOME",
|
| 791 |
-
total_price, related_account=current_user, task_id=task_id
|
|
|
|
|
|
|
| 792 |
)
|
| 793 |
|
| 794 |
task["status"] = "completed"
|
|
|
|
| 37 |
data = f"{tx_id}{account}{tx_type}{amount}{prev_hash}"
|
| 38 |
return hashlib.sha256(data.encode()).hexdigest()
|
| 39 |
|
| 40 |
+
def create_task_transaction(db_session: Session, account: str, tx_type: str, amount: int,
|
| 41 |
+
related_account: str = None, task_id: str = None,
|
| 42 |
+
task_title: str = None, related_user_name: str = None):
|
| 43 |
"""
|
| 44 |
创建任务相关交易记录
|
| 45 |
tx_type: TASK_FREEZE, TASK_DEPOSIT, TASK_PAYMENT, TASK_INCOME, TASK_REFUND
|
|
|
|
| 50 |
prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
|
| 51 |
tx_hash = calculate_tx_hash(tx_id, account, tx_type, amount, prev_hash)
|
| 52 |
|
| 53 |
+
# 根据 tx_type 构造 description
|
| 54 |
+
type_labels = {
|
| 55 |
+
"TASK_FREEZE": "任务冻结",
|
| 56 |
+
"TASK_DEPOSIT": "任务订金",
|
| 57 |
+
"TASK_PAYMENT": "任务尾款",
|
| 58 |
+
"TASK_INCOME": "任务收入",
|
| 59 |
+
"TASK_REFUND": "任务退款",
|
| 60 |
+
"TASK_CANCEL_REFUND": "任务取消退款",
|
| 61 |
+
}
|
| 62 |
+
label = type_labels.get(tx_type, tx_type)
|
| 63 |
+
desc = f"{label}: {task_title}" if task_title else label
|
| 64 |
+
|
| 65 |
new_tx = Transaction(
|
| 66 |
tx_id=tx_id,
|
| 67 |
account=account,
|
|
|
|
| 70 |
related_account=related_account,
|
| 71 |
item_id=task_id, # 复用 item_id 字段存储任务ID
|
| 72 |
prev_hash=prev_hash,
|
| 73 |
+
tx_hash=tx_hash,
|
| 74 |
+
description=desc,
|
| 75 |
+
item_title=task_title,
|
| 76 |
+
item_type="task",
|
| 77 |
+
related_user_name=related_user_name
|
| 78 |
)
|
| 79 |
db_session.add(new_tx)
|
| 80 |
|
|
|
|
| 170 |
# 记录退款交易
|
| 171 |
create_task_transaction(
|
| 172 |
db_session, item["publisher"], "TASK_REFUND",
|
| 173 |
+
item["amount"], task_id=item["task_id"],
|
| 174 |
+
task_title=item["title"]
|
| 175 |
)
|
| 176 |
|
| 177 |
refund_results.append(item)
|
|
|
|
| 430 |
# 💳 记录冻结交易
|
| 431 |
create_task_transaction(
|
| 432 |
db_session, current_user, "TASK_FREEZE",
|
| 433 |
+
-task.totalPrice, task_id=task_id,
|
| 434 |
+
task_title=task.title
|
| 435 |
)
|
| 436 |
db_session.commit()
|
| 437 |
|
|
|
|
| 538 |
# 记录退款交易
|
| 539 |
create_task_transaction(
|
| 540 |
db_session, current_user, "TASK_CANCEL_REFUND",
|
| 541 |
+
frozen_amount, task_id=task_id,
|
| 542 |
+
task_title=task.get("title")
|
| 543 |
)
|
| 544 |
db_session.commit()
|
| 545 |
refund_success = True
|
|
|
|
| 675 |
# 订金从冻结金额中扣除(但还不给接单者,待任务完成后一起支付)
|
| 676 |
wallet.frozen_balance -= deposit
|
| 677 |
|
| 678 |
+
# 获取接单者用户名
|
| 679 |
+
users_db = db.load_data("users.json", default_data={})
|
| 680 |
+
assignee_info = users_db.get(assignee, {})
|
| 681 |
+
assignee_name = assignee_info.get("name", assignee)
|
| 682 |
+
|
| 683 |
# 💳 记录订金支付交易
|
| 684 |
create_task_transaction(
|
| 685 |
db_session, current_user, "TASK_DEPOSIT",
|
| 686 |
+
-deposit, related_account=assignee, task_id=task_id,
|
| 687 |
+
task_title=task.get("title"),
|
| 688 |
+
related_user_name=assignee_name
|
| 689 |
)
|
| 690 |
|
| 691 |
# 更新任务状态
|
|
|
|
| 807 |
|
| 808 |
assignee_wallet.balance += total_price # 全款进入可用余额
|
| 809 |
|
| 810 |
+
# 获取双方用户名
|
| 811 |
+
users_db = db.load_data("users.json", default_data={})
|
| 812 |
+
publisher_info = users_db.get(current_user, {})
|
| 813 |
+
assignee_info = users_db.get(assignee_account, {})
|
| 814 |
+
publisher_name = publisher_info.get("name", current_user)
|
| 815 |
+
assignee_name = assignee_info.get("name", assignee_account)
|
| 816 |
+
|
| 817 |
# 💳 记录交易流水
|
| 818 |
# 1. 发布者支付尾款
|
| 819 |
create_task_transaction(
|
| 820 |
db_session, current_user, "TASK_PAYMENT",
|
| 821 |
+
-remaining, related_account=assignee_account, task_id=task_id,
|
| 822 |
+
task_title=task.get("title"),
|
| 823 |
+
related_user_name=assignee_name
|
| 824 |
)
|
| 825 |
# 2. 接单者收入
|
| 826 |
create_task_transaction(
|
| 827 |
db_session, assignee_account, "TASK_INCOME",
|
| 828 |
+
total_price, related_account=current_user, task_id=task_id,
|
| 829 |
+
task_title=task.get("title"),
|
| 830 |
+
related_user_name=publisher_name
|
| 831 |
)
|
| 832 |
|
| 833 |
task["status"] = "completed"
|
router_wallet.py
CHANGED
|
@@ -161,7 +161,8 @@ async def alipay_notify(request: Request, db: Session = Depends(get_db)):
|
|
| 161 |
|
| 162 |
new_tx = Transaction(
|
| 163 |
tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount,
|
| 164 |
-
prev_hash=prev_hash, tx_hash=tx_hash
|
|
|
|
| 165 |
)
|
| 166 |
db.add(new_tx)
|
| 167 |
db.commit()
|
|
@@ -210,7 +211,8 @@ async def check_order(order_id: str, account: str = None, db: Session = Depends(
|
|
| 210 |
|
| 211 |
new_tx = Transaction(
|
| 212 |
tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount,
|
| 213 |
-
prev_hash=prev_hash, tx_hash=tx_hash
|
|
|
|
| 214 |
)
|
| 215 |
db.add(new_tx)
|
| 216 |
db.commit()
|
|
@@ -330,10 +332,19 @@ async def purchase_item(request: Request, req: PurchaseRequest, db: Session = De
|
|
| 330 |
prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
|
| 331 |
tx_hash = calculate_tx_hash(tx_id, req.account, "PURCHASE", -price, prev_hash)
|
| 332 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 333 |
# 创建交易记录 (字段名为 related_account,与 models_sql.py 中 Transaction 模型保持一致)
|
| 334 |
new_tx = Transaction(
|
| 335 |
tx_id=tx_id, account=req.account, tx_type="PURCHASE", amount=-price,
|
| 336 |
-
related_account=seller_account, item_id=req.item_id, prev_hash=prev_hash, tx_hash=tx_hash
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
)
|
| 338 |
db.add(new_tx)
|
| 339 |
db.commit()
|
|
@@ -397,15 +408,44 @@ async def tip_user(request: Request, req: TipRequest, db: Session = Depends(get_
|
|
| 397 |
prev_hash_sender = last_tx_sender.tx_hash if last_tx_sender else "GENESIS_HASH"
|
| 398 |
prev_hash_target = last_tx_target.tx_hash if last_tx_target else "GENESIS_HASH"
|
| 399 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 400 |
# 发送方交易记录 (字段名为 related_account,与 models_sql.py 中 Transaction 模型保持一致)
|
| 401 |
-
tx_sender = Transaction(
|
| 402 |
-
|
| 403 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 404 |
|
| 405 |
# 接收方交易记录
|
| 406 |
-
tx_target = Transaction(
|
| 407 |
-
|
| 408 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 409 |
|
| 410 |
db.add(tx_sender)
|
| 411 |
db.add(tx_target)
|
|
@@ -536,13 +576,18 @@ async def withdraw(request: Request, req: WithdrawRequest, db: Session = Depends
|
|
| 536 |
prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
|
| 537 |
tx_hash = calculate_tx_hash(tx_id, req.account, "WITHDRAW", -actual_withdraw, prev_hash)
|
| 538 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 539 |
new_tx = Transaction(
|
| 540 |
tx_id=tx_id, account=req.account, tx_type="WITHDRAW", amount=-actual_withdraw,
|
| 541 |
alipay_account=req.alipayAccount,
|
| 542 |
real_name=req.real_name,
|
| 543 |
withdraw_status="pending",
|
| 544 |
net_amount=net_amount, # 记录实际到账金额,用于解冻时准确扣减
|
| 545 |
-
prev_hash=prev_hash, tx_hash=tx_hash
|
|
|
|
| 546 |
)
|
| 547 |
db.add(new_tx)
|
| 548 |
|
|
@@ -552,7 +597,8 @@ async def withdraw(request: Request, req: WithdrawRequest, db: Session = Depends
|
|
| 552 |
fee_tx_hash = calculate_tx_hash(fee_tx_id, req.account, "WITHDRAW_FEE", -fee_amount, tx_hash)
|
| 553 |
fee_tx = Transaction(
|
| 554 |
tx_id=fee_tx_id, account=req.account, tx_type="WITHDRAW_FEE", amount=-fee_amount,
|
| 555 |
-
prev_hash=tx_hash, tx_hash=fee_tx_hash
|
|
|
|
| 556 |
)
|
| 557 |
db.add(fee_tx)
|
| 558 |
|
|
@@ -604,14 +650,32 @@ async def get_transactions(
|
|
| 604 |
# 格式化输出
|
| 605 |
tx_list = []
|
| 606 |
for tx in transactions:
|
| 607 |
-
|
| 608 |
"tx_id": tx.tx_id,
|
| 609 |
"tx_type": tx.tx_type,
|
| 610 |
"amount": tx.amount,
|
| 611 |
"related_account": tx.related_account,
|
| 612 |
"item_id": tx.item_id,
|
| 613 |
-
"created_at": tx.created_at.isoformat() if tx.created_at else None
|
| 614 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 615 |
|
| 616 |
return {
|
| 617 |
"status": "success",
|
|
@@ -828,6 +892,11 @@ async def refund_purchase(request: Request, account: str, item_id: str, db: Sess
|
|
| 828 |
)
|
| 829 |
db.add(new_refund)
|
| 830 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 831 |
# 记录退款交易
|
| 832 |
tx_id = f"REFUND_{int(time.time())}_{uuid.uuid4().hex[:6]}"
|
| 833 |
last_tx = db.query(Transaction).filter(Transaction.account == account).order_by(Transaction.created_at.desc()).first()
|
|
@@ -836,7 +905,11 @@ async def refund_purchase(request: Request, account: str, item_id: str, db: Sess
|
|
| 836 |
|
| 837 |
new_tx = Transaction(
|
| 838 |
tx_id=tx_id, account=account, tx_type="REFUND", amount=refund_amount,
|
| 839 |
-
related_account=seller_account, item_id=item_id, prev_hash=prev_hash, tx_hash=tx_hash
|
|
|
|
|
|
|
|
|
|
|
|
|
| 840 |
)
|
| 841 |
db.add(new_tx)
|
| 842 |
db.commit()
|
|
@@ -938,4 +1011,7 @@ async def complete_withdrawal(
|
|
| 938 |
|
| 939 |
db.commit()
|
| 940 |
|
|
|
|
|
|
|
|
|
|
| 941 |
return {"status": "success", "message": f"提现 {tx_id} 已确认打款完成"}
|
|
|
|
| 161 |
|
| 162 |
new_tx = Transaction(
|
| 163 |
tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount,
|
| 164 |
+
prev_hash=prev_hash, tx_hash=tx_hash,
|
| 165 |
+
description="支付宝充值"
|
| 166 |
)
|
| 167 |
db.add(new_tx)
|
| 168 |
db.commit()
|
|
|
|
| 211 |
|
| 212 |
new_tx = Transaction(
|
| 213 |
tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount,
|
| 214 |
+
prev_hash=prev_hash, tx_hash=tx_hash,
|
| 215 |
+
description="支付宝充值"
|
| 216 |
)
|
| 217 |
db.add(new_tx)
|
| 218 |
db.commit()
|
|
|
|
| 332 |
prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
|
| 333 |
tx_hash = calculate_tx_hash(tx_id, req.account, "PURCHASE", -price, prev_hash)
|
| 334 |
|
| 335 |
+
# 获取卖家用户名
|
| 336 |
+
users_db = json_db.load_data("users.json", default_data={})
|
| 337 |
+
seller_info = users_db.get(seller_account, {})
|
| 338 |
+
seller_user_name = seller_info.get("name", seller_account)
|
| 339 |
+
|
| 340 |
# 创建交易记录 (字段名为 related_account,与 models_sql.py 中 Transaction 模型保持一致)
|
| 341 |
new_tx = Transaction(
|
| 342 |
tx_id=tx_id, account=req.account, tx_type="PURCHASE", amount=-price,
|
| 343 |
+
related_account=seller_account, item_id=req.item_id, prev_hash=prev_hash, tx_hash=tx_hash,
|
| 344 |
+
description=f"购买 {item.get('title', '未知资源')}",
|
| 345 |
+
item_title=item.get('title', ''),
|
| 346 |
+
item_type=item.get('type', ''),
|
| 347 |
+
related_user_name=seller_user_name
|
| 348 |
)
|
| 349 |
db.add(new_tx)
|
| 350 |
db.commit()
|
|
|
|
| 408 |
prev_hash_sender = last_tx_sender.tx_hash if last_tx_sender else "GENESIS_HASH"
|
| 409 |
prev_hash_target = last_tx_target.tx_hash if last_tx_target else "GENESIS_HASH"
|
| 410 |
|
| 411 |
+
# 获取用户名和资源信息
|
| 412 |
+
users_db = json_db.load_data("users.json", default_data={})
|
| 413 |
+
target_user_info = users_db.get(req.target_account, {})
|
| 414 |
+
sender_user_info = users_db.get(req.sender_account, {})
|
| 415 |
+
target_user_name = target_user_info.get("name", req.target_account)
|
| 416 |
+
sender_user_name = sender_user_info.get("name", req.sender_account)
|
| 417 |
+
|
| 418 |
+
# 如果有关联资源,获取资源信息
|
| 419 |
+
item_title = None
|
| 420 |
+
item_type = None
|
| 421 |
+
if req.item_id:
|
| 422 |
+
items_db = json_db.load_data("items.json", default_data=[])
|
| 423 |
+
item = next((i for i in items_db if i["id"] == req.item_id), None)
|
| 424 |
+
if item:
|
| 425 |
+
item_title = item.get("title")
|
| 426 |
+
item_type = item.get("type")
|
| 427 |
+
|
| 428 |
# 发送方交易记录 (字段名为 related_account,与 models_sql.py 中 Transaction 模型保持一致)
|
| 429 |
+
tx_sender = Transaction(
|
| 430 |
+
tx_id=tx_id_sender, account=req.sender_account, tx_type="TIP_OUT", amount=-req.amount,
|
| 431 |
+
related_account=req.target_account, prev_hash=prev_hash_sender,
|
| 432 |
+
tx_hash=calculate_tx_hash(tx_id_sender, req.sender_account, "TIP_OUT", -req.amount, prev_hash_sender),
|
| 433 |
+
description=f"打赏给 {target_user_name}" + (f" 的 {item_title}" if item_title else ""),
|
| 434 |
+
item_title=item_title,
|
| 435 |
+
item_type=item_type,
|
| 436 |
+
related_user_name=target_user_name
|
| 437 |
+
)
|
| 438 |
|
| 439 |
# 接收方交易记录
|
| 440 |
+
tx_target = Transaction(
|
| 441 |
+
tx_id=tx_id_target, account=req.target_account, tx_type="TIP_IN", amount=req.amount,
|
| 442 |
+
related_account=req.sender_account, prev_hash=prev_hash_target,
|
| 443 |
+
tx_hash=calculate_tx_hash(tx_id_target, req.target_account, "TIP_IN", req.amount, prev_hash_target),
|
| 444 |
+
description=f"收到 {sender_user_name} 的打赏" + (f" ({item_title})" if item_title else ""),
|
| 445 |
+
item_title=item_title,
|
| 446 |
+
item_type=item_type,
|
| 447 |
+
related_user_name=sender_user_name if not req.is_anonymous else "匿名用户"
|
| 448 |
+
)
|
| 449 |
|
| 450 |
db.add(tx_sender)
|
| 451 |
db.add(tx_target)
|
|
|
|
| 576 |
prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
|
| 577 |
tx_hash = calculate_tx_hash(tx_id, req.account, "WITHDRAW", -actual_withdraw, prev_hash)
|
| 578 |
|
| 579 |
+
# 脱敏支付宝账号和姓名
|
| 580 |
+
masked_alipay = req.alipayAccount[:3] + "****" + req.alipayAccount[-4:] if len(req.alipayAccount) > 7 else req.alipayAccount
|
| 581 |
+
masked_name = req.real_name[0] + "*" * (len(req.real_name) - 1) if req.real_name else ""
|
| 582 |
+
|
| 583 |
new_tx = Transaction(
|
| 584 |
tx_id=tx_id, account=req.account, tx_type="WITHDRAW", amount=-actual_withdraw,
|
| 585 |
alipay_account=req.alipayAccount,
|
| 586 |
real_name=req.real_name,
|
| 587 |
withdraw_status="pending",
|
| 588 |
net_amount=net_amount, # 记录实际到账金额,用于解冻时准确扣减
|
| 589 |
+
prev_hash=prev_hash, tx_hash=tx_hash,
|
| 590 |
+
description=f"提现到支付宝 {masked_alipay} ({masked_name})"
|
| 591 |
)
|
| 592 |
db.add(new_tx)
|
| 593 |
|
|
|
|
| 597 |
fee_tx_hash = calculate_tx_hash(fee_tx_id, req.account, "WITHDRAW_FEE", -fee_amount, tx_hash)
|
| 598 |
fee_tx = Transaction(
|
| 599 |
tx_id=fee_tx_id, account=req.account, tx_type="WITHDRAW_FEE", amount=-fee_amount,
|
| 600 |
+
prev_hash=tx_hash, tx_hash=fee_tx_hash,
|
| 601 |
+
description="提现手续费"
|
| 602 |
)
|
| 603 |
db.add(fee_tx)
|
| 604 |
|
|
|
|
| 650 |
# 格式化输出
|
| 651 |
tx_list = []
|
| 652 |
for tx in transactions:
|
| 653 |
+
tx_data = {
|
| 654 |
"tx_id": tx.tx_id,
|
| 655 |
"tx_type": tx.tx_type,
|
| 656 |
"amount": tx.amount,
|
| 657 |
"related_account": tx.related_account,
|
| 658 |
"item_id": tx.item_id,
|
| 659 |
+
"created_at": tx.created_at.isoformat() if tx.created_at else None,
|
| 660 |
+
# 新增字段
|
| 661 |
+
"description": tx.description,
|
| 662 |
+
"item_title": tx.item_title,
|
| 663 |
+
"item_type": tx.item_type,
|
| 664 |
+
"related_user_name": tx.related_user_name,
|
| 665 |
+
}
|
| 666 |
+
|
| 667 |
+
# 提现类型额外返回脱敏信息
|
| 668 |
+
if tx.tx_type == "WITHDRAW":
|
| 669 |
+
# 脱敏支付宝账号
|
| 670 |
+
if tx.alipay_account:
|
| 671 |
+
a = tx.alipay_account
|
| 672 |
+
tx_data["alipay_account"] = a[:3] + "****" + a[-4:] if len(a) > 7 else a
|
| 673 |
+
if tx.real_name:
|
| 674 |
+
tx_data["real_name"] = tx.real_name[0] + "*" * (len(tx.real_name) - 1)
|
| 675 |
+
tx_data["withdraw_status"] = tx.withdraw_status
|
| 676 |
+
tx_data["net_amount"] = tx.net_amount
|
| 677 |
+
|
| 678 |
+
tx_list.append(tx_data)
|
| 679 |
|
| 680 |
return {
|
| 681 |
"status": "success",
|
|
|
|
| 892 |
)
|
| 893 |
db.add(new_refund)
|
| 894 |
|
| 895 |
+
# 获取卖家用户名
|
| 896 |
+
users_db = json_db.load_data("users.json", default_data={})
|
| 897 |
+
seller_info = users_db.get(seller_account, {})
|
| 898 |
+
seller_user_name = seller_info.get("name", seller_account)
|
| 899 |
+
|
| 900 |
# 记录退款交易
|
| 901 |
tx_id = f"REFUND_{int(time.time())}_{uuid.uuid4().hex[:6]}"
|
| 902 |
last_tx = db.query(Transaction).filter(Transaction.account == account).order_by(Transaction.created_at.desc()).first()
|
|
|
|
| 905 |
|
| 906 |
new_tx = Transaction(
|
| 907 |
tx_id=tx_id, account=account, tx_type="REFUND", amount=refund_amount,
|
| 908 |
+
related_account=seller_account, item_id=item_id, prev_hash=prev_hash, tx_hash=tx_hash,
|
| 909 |
+
description=f"退款: {item.get('title', '未知资源')}",
|
| 910 |
+
item_title=item.get('title', ''),
|
| 911 |
+
item_type=item.get('type', ''),
|
| 912 |
+
related_user_name=seller_user_name
|
| 913 |
)
|
| 914 |
db.add(new_tx)
|
| 915 |
db.commit()
|
|
|
|
| 1011 |
|
| 1012 |
db.commit()
|
| 1013 |
|
| 1014 |
+
# 📝 P2优化:提现完成审计日志
|
| 1015 |
+
logger.info(f"WITHDRAW_COMPLETED | admin={current_user} | tx_id={tx_id} | account={tx.account} | amount={tx.amount} | net_amount={tx.net_amount} | order_id={req.payment_order_id}")
|
| 1016 |
+
|
| 1017 |
return {"status": "success", "message": f"提现 {tx_id} 已确认打款完成"}
|