0717c09721
改动:新增厂商推送配置、设备 push_vendor/push_token 字段、device push-test 接口、心跳超时厂商直推发送逻辑和对应测试。 验证:python -m pytest tests/test_device_push.py tests/test_auth.py tests/test_health.py 通过。 --------- Co-authored-by: guke <guke@wonderable.ai> Co-authored-by: 左辰勇 <exinglang@gmail.com> Co-authored-by: lowmaster-chen <1119780489@qq.com> Reviewed-on: #118 Co-authored-by: Ghost <> Co-committed-by: Ghost <>
136 lines
6.4 KiB
Python
136 lines
6.4 KiB
Python
"""给指定用户(默认 11111111111)造「后台可驱动」的推送联调数据。
|
||
|
||
覆盖能从**管理后台点一下就触发手机推送**的 3 类事件,每类 10 条待审记录:
|
||
|
||
事件(PRD #) 后台动作 造的数据
|
||
────────────────────────────────────────────────────────────────────
|
||
#10 反馈奖励 反馈工单 → 采纳(填回复留言 + 金币) 10 条 pending feedback(标「请采纳」)
|
||
#9 官方回复 反馈工单 → 拒绝(填未采纳原因/留言) 10 条 pending feedback(标「请拒绝」)
|
||
#11 爆料审核通过 上报更低价 → 通过 10 条 pending price_report
|
||
|
||
触发链路:admin 审核 → 发金币/改状态 → services/notification_events 落站内消息 + 厂商直推
|
||
→ 该用户已注册设备(device_liveness)收到 push。
|
||
|
||
其余 3 类(#3 提现成功 / #4 提现失败 / #12 好友下单到账)后台无法在本环境驱动
|
||
(wxpay 未配 / 提现单唯一约束 / 后台无入口),用 scripts/fire_push_events.py 直接触发。
|
||
|
||
幂等:每次先删掉本脚本上一轮造的记录(按内容标记 [PUSH测试] 识别,不动用户真实反馈/爆料),再重建。
|
||
.venv\\Scripts\\python.exe scripts\\seed_push_admin_test.py
|
||
.venv\\Scripts\\python.exe scripts\\seed_push_admin_test.py --phone 11111111111 --count 10
|
||
.venv\\Scripts\\python.exe scripts\\seed_push_admin_test.py --clean-only
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import logging
|
||
import sys
|
||
|
||
from sqlalchemy import delete, select
|
||
|
||
from app.db.session import SessionLocal
|
||
from app.models.feedback import Feedback
|
||
from app.models.price_report import PriceReport
|
||
from app.repositories import user as user_repo
|
||
|
||
logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING) # 静音 SQL 回显,输出更干净
|
||
|
||
if hasattr(sys.stdout, "reconfigure"):
|
||
sys.stdout.reconfigure(encoding="utf-8")
|
||
|
||
DEFAULT_PHONE = "11111111111"
|
||
MARK = "[PUSH测试]" # 本脚本造的数据统一带此标记,幂等清理按它识别(不误删真实数据)
|
||
|
||
|
||
def clean(db, uid: int) -> tuple[int, int]:
|
||
"""删掉本脚本上一轮造的带标记记录(任何状态都删,彻底重置)。返回 (删反馈数, 删爆料数)。"""
|
||
fb_ids = list(db.execute(
|
||
select(Feedback.id).where(Feedback.user_id == uid, Feedback.content.like(f"{MARK}%"))
|
||
).scalars())
|
||
rep_ids = list(db.execute(
|
||
select(PriceReport.id).where(
|
||
PriceReport.user_id == uid, PriceReport.store_name.like(f"{MARK}%")
|
||
)
|
||
).scalars())
|
||
if fb_ids:
|
||
db.execute(delete(Feedback).where(Feedback.id.in_(fb_ids)))
|
||
if rep_ids:
|
||
db.execute(delete(PriceReport).where(PriceReport.id.in_(rep_ids)))
|
||
db.commit()
|
||
return len(fb_ids), len(rep_ids)
|
||
|
||
|
||
def seed(db, uid: int, count: int) -> None:
|
||
# #10 反馈奖励:采纳这些 → 手机收「反馈奖励已到账」。采纳时记得在后台填「给用户的回复留言」
|
||
# (PRD 要求发奖必带官方留言),否则通知里不带留言行。
|
||
for i in range(1, count + 1):
|
||
db.add(Feedback(
|
||
user_id=uid,
|
||
content=f"{MARK} 请【采纳】我 → 触发 #10 反馈奖励推送。测试反馈内容 {i:02d}:比价页能加个历史记录就好了。",
|
||
contact="",
|
||
source="profile",
|
||
status="pending",
|
||
))
|
||
# #9 官方回复:拒绝这些 → 手机收「您的反馈有回复啦」。拒绝时填「未采纳原因」+「回复留言」。
|
||
for i in range(1, count + 1):
|
||
db.add(Feedback(
|
||
user_id=uid,
|
||
content=f"{MARK} 请【拒绝】我 → 触发 #9 官方回复推送。测试反馈内容 {i:02d}:希望支持某某小众平台比价。",
|
||
contact="",
|
||
source="comparison",
|
||
scene="other",
|
||
status="pending",
|
||
))
|
||
# #11 爆料审核通过:通过这些 → 手机收「爆料审核通过」(发固定金币)。
|
||
for i in range(1, count + 1):
|
||
db.add(PriceReport(
|
||
user_id=uid,
|
||
comparison_record_id=None,
|
||
store_name=f"{MARK}测试火锅店{i:02d}",
|
||
dish_summary="招牌套餐 × 1",
|
||
original_platform_id="meituan-waimai",
|
||
original_platform_name="美团外卖",
|
||
original_price_cents=9900,
|
||
reported_platform_id="jd-waimai",
|
||
reported_platform_name="京东外卖",
|
||
reported_price_cents=8800,
|
||
images=[],
|
||
status="pending",
|
||
))
|
||
db.commit()
|
||
|
||
|
||
def main() -> None:
|
||
parser = argparse.ArgumentParser(description="造后台可驱动的推送联调数据(反馈×2 + 爆料)")
|
||
parser.add_argument("--phone", default=DEFAULT_PHONE, help=f"目标用户手机号(默认 {DEFAULT_PHONE})")
|
||
parser.add_argument("--count", type=int, default=10, help="每类造多少条(默认 10)")
|
||
parser.add_argument("--clean-only", action="store_true", help="只清理本脚本造的数据,不重建")
|
||
args = parser.parse_args()
|
||
|
||
db = SessionLocal()
|
||
try:
|
||
user = user_repo.get_user_by_phone(db, args.phone)
|
||
if user is None:
|
||
print(f"❌ 用户 {args.phone} 不存在。请先用该手机号在 App 登录一次再跑本脚本。")
|
||
return
|
||
uid = user.id
|
||
|
||
nf, nr = clean(db, uid)
|
||
print(f"🧹 已清理上一轮 [PUSH测试] 数据:反馈 {nf} 条、爆料 {nr} 条")
|
||
if args.clean_only:
|
||
print("✅ 仅清理,已完成。")
|
||
return
|
||
|
||
seed(db, uid, args.count)
|
||
print(f"\n✅ 已为 {args.phone}(id={uid})造好后台联调数据(每类 {args.count} 条):")
|
||
print(f" • 反馈工单「请采纳」× {args.count} → 后台【采纳】(填回复留言+金币)→ 手机收 #10 反馈奖励")
|
||
print(f" • 反馈工单「请拒绝」× {args.count} → 后台【拒绝】(填未采纳原因/留言)→ 手机收 #9 官方回复")
|
||
print(f" • 上报更低价 × {args.count} → 后台【通过】→ 手机收 #11 爆料审核通过")
|
||
print("\n👉 打开管理后台(:8771)对应列表即可看到这些待审记录,逐条审核就会推到手机。")
|
||
print(" #3/#4/#12 本环境后台驱动不了,用:.venv\\Scripts\\python.exe scripts\\fire_push_events.py")
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|