feat: 福利钱包+签到+省钱战绩+激励广告发奖+微信提现 后端
- 福利钱包: 金币/现金余额、流水、兑换 (api/v1/wallet.py, crud/wallet.py, models/wallet.py, schemas/welfare.py) - 每日签到: 连续天数 + 档位奖励 (api/v1/signin.py, crud/signin.py, models/signin.py) - 任务系统: "打开消息提醒"等任务领奖 (api/v1/tasks.py, crud/task.py, models/task.py) - 省钱战绩: 省钱汇总/战绩/店铺菜品 (api/v1/savings.py, crud/savings.py, models/savings.py) - 激励广告发奖: 穿山甲服务端回调 + 发奖规则 + 限流 (api/v1/ad.py, core/pangle.py, core/rewards.py, core/ratelimit.py, crud/ad_reward.py, schemas/ad.py, docs/ad_reward_golive_checklist.md) - 微信提现: 商家转账到零钱 V3 (core/wxpay.py); user 表加微信 openid/nickname/avatar - DB 迁移: 8 个 alembic (welfare 表/cash_transaction/openid 唯一约束/savings 店铺菜品/savings_record/ad_reward/withdraw_order+openid/user 微信字段) - 运维脚本: reconcile_withdraws(对账) + reset_signin/reset_welfare + sim_pangle_callback(模拟穿山甲回调) - 测试: test_welfare / test_withdraw / test_ad_reward - 配置: .env.example + config.py 新增福利/广告/微信支付项; main.py 挂 5 个新路由 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
"""提现对账(#4 孤儿单兜底)。
|
||||
|
||||
扫描超过 N 分钟仍 pending 的提现单,逐单查微信归一化:
|
||||
- 微信 SUCCESS → 置 success
|
||||
- 微信失败/取消/关闭/无此单 → 退回现金 + 置 failed
|
||||
- WAIT_USER_CONFIRM(久未确认)→ 撤销 + 退款
|
||||
防止"扣了款但转账没发起/没确认"的单永久锁住用户余额。
|
||||
|
||||
用法(建议 cron / systemd timer 每 5~10 分钟跑一次):
|
||||
python -m scripts.reconcile_withdraws # 默认处理 >15 分钟的 pending
|
||||
python -m scripts.reconcile_withdraws 30 # 处理 >30 分钟的 pending
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
# Windows 控制台按 UTF-8 输出中文/¥
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8") # type: ignore[attr-defined]
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
from app.crud import wallet as crud_wallet
|
||||
from app.db.session import SessionLocal
|
||||
|
||||
|
||||
def main() -> None:
|
||||
minutes = int(sys.argv[1]) if len(sys.argv) > 1 else 15
|
||||
db = SessionLocal()
|
||||
try:
|
||||
result = crud_wallet.reconcile_pending_withdraws(db, older_than_minutes=minutes)
|
||||
print(f"对账完成: 检查 {result['checked']} 笔 pending(>{minutes}分钟), 归结 {result['resolved']} 笔")
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user