test_market_writes.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. # -*- coding: utf-8 -*-
  2. """营销与会员写接口端到端测试(优惠券 / 充值套餐 / 会员等级 / 会员充值 / 改等级 / 删除会员 / 领取记录)。
  3. 自带造数与清理:测试记录以 TESTJ 命名,跑完物理删除;用户余额、积分、等级恢复原值。
  4. 用法:python test_market_writes.py
  5. """
  6. import json
  7. import re
  8. from pathlib import Path
  9. import pymysql
  10. import requests
  11. JAVA = "http://127.0.0.1:18080"
  12. TOKEN = "testsession123"
  13. STORE_ID = 10001
  14. ROOT = Path(r"C:\Users\Administrator\WorkBuddy\2026-10-17-12-27-10\java-rewrite")
  15. YML = ROOT / "yoshop-java" / "src" / "main" / "resources" / "application.yml"
  16. SESSION = requests.Session()
  17. SESSION.trust_env = False
  18. PASS = FAIL = 0
  19. FAILS = []
  20. def db():
  21. pwd = re.findall(r"password: *(.+)", YML.read_text(encoding="utf-8"))[0].strip().strip('"')
  22. return pymysql.connect(host="192.168.1.177", port=3306, user="root", password=pwd,
  23. database="shop", autocommit=True)
  24. CONN = db()
  25. def query(sql, args=None):
  26. cur = CONN.cursor()
  27. cur.execute(sql, args or ())
  28. cols = [d[0] for d in cur.description]
  29. return [dict(zip(cols, row)) for row in cur.fetchall()]
  30. def execute(sql, args=None):
  31. cur = CONN.cursor()
  32. cur.execute(sql, args or ())
  33. return cur.rowcount
  34. def get(path, params=None):
  35. r = SESSION.get(JAVA + path, headers={"Access-Token": TOKEN}, params=params, timeout=60)
  36. return r.json()
  37. def post(path, body):
  38. r = SESSION.post(JAVA + path, headers={"Access-Token": TOKEN}, json=body, timeout=60)
  39. return r.json()
  40. def check(name, ok, detail=""):
  41. global PASS, FAIL
  42. if ok:
  43. PASS += 1
  44. print(f" [ok] {name}")
  45. else:
  46. FAIL += 1
  47. FAILS.append(name)
  48. print(f" [FAIL] {name} {detail}")
  49. def eq(name, actual, expect):
  50. check(name, actual == expect, f"期望 {expect!r} 实际 {actual!r}")
  51. def main():
  52. # ---------------------------------------------------------------- 基线
  53. users = query("select user_id, balance, points, grade_id from yoshop_user where user_id=10001")
  54. if not users:
  55. print("缺少测试会员 10001,终止")
  56. return
  57. base = users[0]
  58. base_balance = base["balance"]
  59. max_balance_log = (query("select coalesce(max(log_id),0) m from yoshop_user_balance_log")[0]["m"])
  60. max_points_log = (query("select coalesce(max(log_id),0) m from yoshop_user_points_log")[0]["m"])
  61. max_grade_log = (query("select coalesce(max(log_id),0) m from yoshop_user_grade_log")[0]["m"])
  62. print(f"基线:余额 {base_balance} 积分 {base['points']} 等级 {base['grade_id']}")
  63. coupon_ids = []
  64. plan_ids = []
  65. grade_ids = []
  66. test_user = 10999
  67. try:
  68. # ------------------------------------------------------------ 优惠券
  69. print("\n[优惠券] 新增(满减 · 领取后生效 · 全部商品)")
  70. res = post("/store/market.coupon/add", {"form": {
  71. "name": "TESTJ券A", "coupon_type": 10, "reduce_price": 10, "min_price": 100,
  72. "expire_type": 10, "expire_day": 7, "apply_range": 10, "total_num": -1,
  73. "status": 1, "describe": "自动化用例", "sort": 100}})
  74. eq("add 返回成功", res.get("status"), 200)
  75. eq("add 文案", res.get("message"), "添加成功")
  76. rows = query("select * from yoshop_coupon where name='TESTJ券A'")
  77. check("库内已写入", len(rows) == 1)
  78. a = rows[0]
  79. coupon_ids.append(a["coupon_id"])
  80. eq("start_time 清零", a["start_time"], 0)
  81. eq("end_time 清零", a["end_time"], 0)
  82. eq("expire_day 保留", a["expire_day"], 7)
  83. eq("apply_range_config 空数组", a["apply_range_config"], "[]")
  84. eq("store_id", a["store_id"], STORE_ID)
  85. eq("reduce_price", str(a["reduce_price"]), "10.00")
  86. check("create_time 已写", a["create_time"] > 0)
  87. detail = get("/store/market.coupon/detail", {"couponId": a["coupon_id"]})["data"]["detail"]
  88. eq("detail 折扣为 0", detail["discount"], 0)
  89. eq("detail 开始时间为 null", detail["start_time"], None)
  90. eq("detail 适用范围空数组", detail["apply_range_config"], [])
  91. eq("detail state 正常", detail["state"], {"text": "正常", "value": 1})
  92. print("\n[优惠券] 新增(折扣 · 固定时间 · 指定商品)")
  93. res = post("/store/market.coupon/add", {"form": {
  94. "name": "TESTJ券B", "coupon_type": 20, "discount": 9.9, "min_price": 50,
  95. "expire_type": 20, "betweenTime": ["2026-10-01", "2026-10-31"],
  96. "apply_range": 20, "apply_range_config": {"goodsIds": ["10004"]},
  97. "total_num": 5, "status": 1, "describe": "", "sort": 90}})
  98. eq("add 返回成功", res.get("status"), 200)
  99. rows = query("select * from yoshop_coupon where name='TESTJ券B'")
  100. check("库内已写入", len(rows) == 1)
  101. b = rows[0]
  102. coupon_ids.append(b["coupon_id"])
  103. eq("discount 乘 10 入库", b["discount"], 99)
  104. eq("expire_day 置 1", b["expire_day"], 1)
  105. eq("apply_range_config 存对象", json.loads(b["apply_range_config"]), {"goodsIds": ["10004"]})
  106. check("end_time 补足当天 23:59:59", (b["end_time"] - b["start_time"]) % 86400 == 86399)
  107. detail = get("/store/market.coupon/detail", {"couponId": b["coupon_id"]})["data"]["detail"]
  108. eq("detail 折扣率 9.9", detail["discount"], 9.9)
  109. eq("detail 开始时间 Y/m/d", detail["start_time"], "2026/10/01")
  110. eq("detail 结束时间 Y/m/d", detail["end_time"], "2026/10/31")
  111. print("\n[优惠券] 固定时间缺少区间")
  112. res = post("/store/market.coupon/add", {"form": {
  113. "name": "TESTJ券C", "coupon_type": 10, "reduce_price": 5, "min_price": 10,
  114. "expire_type": 20, "apply_range": 10, "total_num": -1, "status": 1, "sort": 100}})
  115. eq("返回失败", res.get("status"), 500)
  116. eq("提示有效期", res.get("message"), "请选择有效期范围")
  117. eq("未写入脏数据", len(query("select coupon_id from yoshop_coupon where name='TESTJ券C'")), 0)
  118. print("\n[优惠券] 编辑")
  119. res = post("/store/market.coupon/edit", {"couponId": a["coupon_id"], "form": {
  120. "name": "TESTJ券A改", "coupon_type": 10, "reduce_price": 20, "min_price": 200,
  121. "expire_type": 10, "expire_day": 3, "apply_range": 20,
  122. "apply_range_config": {"goodsIds": ["10004", "10005"]},
  123. "total_num": 100, "status": 1, "describe": "改过", "sort": 88}})
  124. eq("edit 返回成功", res.get("status"), 200)
  125. eq("edit 文案", res.get("message"), "更新成功")
  126. a2 = query("select * from yoshop_coupon where coupon_id=%s", (a["coupon_id"],))[0]
  127. eq("名称已改", a2["name"], "TESTJ券A改")
  128. eq("减免金额已改", str(a2["reduce_price"]), "20.00")
  129. eq("适用范围已改", a2["apply_range"], 20)
  130. eq("适用范围配置已改", json.loads(a2["apply_range_config"]), {"goodsIds": ["10004", "10005"]})
  131. eq("排序已改", a2["sort"], 88)
  132. print("\n[优惠券] 编辑为全部商品 → 配置清空")
  133. post("/store/market.coupon/edit", {"couponId": a["coupon_id"], "form": {
  134. "name": "TESTJ券A改", "coupon_type": 10, "reduce_price": 20, "min_price": 200,
  135. "expire_type": 10, "expire_day": 3, "apply_range": 10,
  136. "apply_range_config": {"goodsIds": ["10004"]},
  137. "total_num": 100, "status": 1, "describe": "改过", "sort": 88}})
  138. a3 = query("select apply_range_config from yoshop_coupon where coupon_id=%s", (a["coupon_id"],))[0]
  139. eq("配置被清空", a3["apply_range_config"], "[]")
  140. print("\n[优惠券] 编辑不存在的券")
  141. res = post("/store/market.coupon/edit", {"couponId": 999999, "form": {"name": "x"}})
  142. eq("返回失败", res.get("status"), 500)
  143. print("\n[优惠券] 删除")
  144. res = post("/store/market.coupon/delete", {"couponId": a["coupon_id"]})
  145. eq("delete 返回成功", res.get("status"), 200)
  146. eq("软删除标记", query("select is_delete from yoshop_coupon where coupon_id=%s",
  147. (a["coupon_id"],))[0]["is_delete"], 1)
  148. listed = get("/store/market.coupon/list", {"page": 1, "search": "TESTJ券A"})["data"]["list"]["data"]
  149. eq("列表不再出现", len(listed), 0)
  150. print("\n[优惠券] 删除不存在的券")
  151. eq("返回失败", post("/store/market.coupon/delete", {"couponId": 999999}).get("status"), 500)
  152. # ---------------------------------------------------------- 充值套餐
  153. print("\n[充值套餐] 新增 / 编辑 / 删除")
  154. res = post("/store/market.recharge.plan/add", {"form": {
  155. "plan_name": "TESTJ套餐A", "money": 100, "gift_money": 10, "sort": 100}})
  156. eq("add 返回成功", res.get("status"), 200)
  157. rows = query("select * from yoshop_recharge_plan where plan_name='TESTJ套餐A'")
  158. check("库内已写入", len(rows) == 1)
  159. plan = rows[0]
  160. plan_ids.append(plan["plan_id"])
  161. eq("充值金额", str(plan["money"]), "100.00")
  162. eq("赠送金额", str(plan["gift_money"]), "10.00")
  163. eq("store_id", plan["store_id"], STORE_ID)
  164. res = post("/store/market.recharge.plan/edit", {"planId": plan["plan_id"], "form": {
  165. "plan_name": "TESTJ套餐A改", "money": 200, "gift_money": 30, "sort": 66}})
  166. eq("edit 返回成功", res.get("status"), 200)
  167. plan2 = query("select * from yoshop_recharge_plan where plan_id=%s", (plan["plan_id"],))[0]
  168. eq("名称已改", plan2["plan_name"], "TESTJ套餐A改")
  169. eq("金额已改", str(plan2["money"]), "200.00")
  170. eq("排序已改", plan2["sort"], 66)
  171. res = post("/store/market.recharge.plan/delete", {"planId": plan["plan_id"]})
  172. eq("delete 返回成功", res.get("status"), 200)
  173. eq("软删除标记", query("select is_delete from yoshop_recharge_plan where plan_id=%s",
  174. (plan["plan_id"],))[0]["is_delete"], 1)
  175. eq("删除不存在的套餐", post("/store/market.recharge.plan/delete", {"planId": 999999}).get("status"), 500)
  176. # ---------------------------------------------------------- 会员等级
  177. print("\n[会员等级] 新增 / 权重重复 / 编辑 / 删除")
  178. res = post("/store/user.grade/add", {"form": {
  179. "name": "TESTJ等级", "weight": 9,
  180. "upgrade": {"expend_money": 50000}, "equity": {"discount": "9.5"}, "status": 1}})
  181. eq("add 返回成功", res.get("status"), 200)
  182. rows = query("select * from yoshop_user_grade where name='TESTJ等级'")
  183. check("库内已写入", len(rows) == 1)
  184. grade = rows[0]
  185. grade_ids.append(grade["grade_id"])
  186. eq("权重", grade["weight"], 9)
  187. eq("升级条件 JSON", json.loads(grade["upgrade"]), {"expend_money": 50000})
  188. eq("等级权益 JSON", json.loads(grade["equity"]), {"discount": "9.5"})
  189. eq("store_id", grade["store_id"], STORE_ID)
  190. res = post("/store/user.grade/add", {"form": {"name": "TESTJ等级2", "weight": 9,
  191. "upgrade": {}, "equity": {}, "status": 1}})
  192. eq("权重重复被拦", res.get("status"), 500)
  193. eq("权重重复提示", res.get("message"), "等级权重已存在")
  194. res = post("/store/user.grade/edit", {"gradeId": grade["grade_id"], "form": {
  195. "name": "TESTJ等级改", "weight": 8,
  196. "upgrade": {"expend_money": 60000}, "equity": {"discount": "9.4"}, "status": 1}})
  197. eq("edit 返回成功", res.get("status"), 200)
  198. g2 = query("select * from yoshop_user_grade where grade_id=%s", (grade["grade_id"],))[0]
  199. eq("名称已改", g2["name"], "TESTJ等级改")
  200. eq("权重已改", g2["weight"], 8)
  201. res = post("/store/user.grade/edit", {"gradeId": grade["grade_id"], "form": {
  202. "name": "TESTJ等级改", "weight": 1,
  203. "upgrade": {"expend_money": 60000}, "equity": {"discount": "9.4"}, "status": 1}})
  204. eq("编辑撞已有权重被拦", res.get("status"), 500)
  205. # 有会员占用时不允许删除:先造一个挂在该等级下的会员
  206. execute("delete from yoshop_user where user_id=%s", (test_user,))
  207. execute("""insert into yoshop_user
  208. (user_id,mobile,nick_name,avatar_id,gender,country,province,city,address_id,
  209. balance,points,pay_money,expend_money,grade_id,platform,last_login_time,
  210. is_delete,store_id,create_time,update_time)
  211. values (%s,'19900000000','TESTJ会员',0,0,'','','',0,0,0,0,0,%s,'H5',0,0,%s,0,0)""",
  212. (test_user, grade["grade_id"], STORE_ID))
  213. res = post("/store/user.grade/delete", {"gradeId": grade["grade_id"]})
  214. eq("等级下有会员时禁止删除", res.get("status"), 500)
  215. eq("提示文案", res.get("message"), "该会员等级下存在用户,不允许删除")
  216. eq("未被删除", query("select is_delete from yoshop_user_grade where grade_id=%s",
  217. (grade["grade_id"],))[0]["is_delete"], 0)
  218. execute("update yoshop_user set grade_id=0 where user_id=%s", (test_user,))
  219. res = post("/store/user.grade/delete", {"gradeId": grade["grade_id"]})
  220. eq("无会员时可删除", res.get("status"), 200)
  221. eq("软删除标记", query("select is_delete from yoshop_user_grade where grade_id=%s",
  222. (grade["grade_id"],))[0]["is_delete"], 1)
  223. # ------------------------------------------------------------ 会员充值
  224. print("\n[会员充值] 余额 · 增加")
  225. before = query("select balance from yoshop_user where user_id=10001")[0]["balance"]
  226. res = post("/store/user/recharge", {"userId": 10001, "target": "balance",
  227. "form": {"balance": {"mode": "inc", "money": 50, "remark": "TESTJ充值"}}})
  228. eq("返回成功", res.get("status"), 200)
  229. eq("文案", res.get("message"), "操作成功")
  230. after = query("select balance from yoshop_user where user_id=10001")[0]["balance"]
  231. eq("余额增加 50", str(after - before), "50.00")
  232. logs = query("""select * from yoshop_user_balance_log where user_id=10001
  233. and log_id>%s order by log_id desc limit 1""", (max_balance_log,))
  234. eq("写入余额流水", len(logs), 1)
  235. eq("流水场景=管理员操作", logs[0]["scene"], 30)
  236. eq("流水金额", str(logs[0]["money"]), "50.00")
  237. check("流水描述含管理员", logs[0]["describe"].startswith("后台管理员 [")
  238. and logs[0]["describe"].endswith("] 操作"), logs[0]["describe"])
  239. eq("流水备注", logs[0]["remark"], "TESTJ充值")
  240. print("\n[会员充值] 余额 · 减少")
  241. before = query("select balance from yoshop_user where user_id=10001")[0]["balance"]
  242. res = post("/store/user/recharge", {"userId": 10001, "target": "balance",
  243. "form": {"balance": {"mode": "dec", "money": 20, "remark": ""}}})
  244. eq("返回成功", res.get("status"), 200)
  245. after = query("select balance from yoshop_user where user_id=10001")[0]["balance"]
  246. eq("余额减少 20", str(before - after), "20.00")
  247. logs = query("""select money from yoshop_user_balance_log where user_id=10001
  248. and log_id>%s order by log_id desc limit 1""", (max_balance_log,))
  249. eq("流水记录负数", str(logs[0]["money"]), "-20.00")
  250. print("\n[会员充值] 余额 · 最终金额")
  251. res = post("/store/user/recharge", {"userId": 10001, "target": "balance",
  252. "form": {"balance": {"mode": "final", "money": 888, "remark": ""}}})
  253. eq("返回成功", res.get("status"), 200)
  254. eq("余额变为 888", str(query("select balance from yoshop_user where user_id=10001")[0]["balance"]), "888.00")
  255. print("\n[会员充值] 金额非法")
  256. res = post("/store/user/recharge", {"userId": 10001, "target": "balance",
  257. "form": {"balance": {"mode": "inc", "money": "", "remark": ""}}})
  258. eq("空金额被拦", res.get("status"), 500)
  259. eq("提示文案", res.get("message"), "请输入正确的金额")
  260. res = post("/store/user/recharge", {"userId": 10001, "target": "unknown", "form": {}})
  261. eq("非法 target 被拦", res.get("status"), 500)
  262. print("\n[会员充值] 积分 · 增加 / 最终值")
  263. res = post("/store/user/recharge", {"userId": 10001, "target": "points",
  264. "form": {"points": {"mode": "inc", "value": 30, "remark": "TESTJ积分"}}})
  265. eq("返回成功", res.get("status"), 200)
  266. eq("积分 +30", query("select points from yoshop_user where user_id=10001")[0]["points"], 30)
  267. logs = query("""select * from yoshop_user_points_log where user_id=10001
  268. and log_id>%s order by log_id desc limit 1""", (max_points_log,))
  269. eq("写入积分流水", len(logs), 1)
  270. eq("流水积分值", logs[0]["value"], 30)
  271. eq("流水描述", logs[0]["describe"].startswith("后台管理员 ["), True)
  272. res = post("/store/user/recharge", {"userId": 10001, "target": "points",
  273. "form": {"points": {"mode": "final", "value": 0, "remark": ""}}})
  274. eq("返回成功", res.get("status"), 200)
  275. eq("积分归零", query("select points from yoshop_user where user_id=10001")[0]["points"], 0)
  276. res = post("/store/user/recharge", {"userId": 10001, "target": "points",
  277. "form": {"points": {"mode": "inc", "value": "", "remark": ""}}})
  278. eq("空积分被拦", res.get("status"), 500)
  279. eq("提示文案", res.get("message"), "请输入正确的积分数量")
  280. # ------------------------------------------------------------ 改等级
  281. print("\n[会员等级变更]")
  282. res = post("/store/user/grade", {"userId": 10001, "form": {"grade_id": 10002, "remark": "TESTJ调级"}})
  283. eq("返回成功", res.get("status"), 200)
  284. eq("等级已改", query("select grade_id from yoshop_user where user_id=10001")[0]["grade_id"], 10002)
  285. glog = query("""select * from yoshop_user_grade_log where user_id=10001
  286. and log_id>%s order by log_id desc limit 1""", (max_grade_log,))
  287. eq("写入等级变更记录", len(glog), 1)
  288. eq("变更前等级", glog[0]["old_grade_id"], 0)
  289. eq("变更后等级", glog[0]["new_grade_id"], 10002)
  290. eq("变更类型=管理员", glog[0]["change_type"], 10)
  291. eq("变更备注", glog[0]["remark"], "TESTJ调级")
  292. post("/store/user/grade", {"userId": 10001, "form": {"grade_id": 0, "remark": ""}})
  293. eq("已恢复原等级", query("select grade_id from yoshop_user where user_id=10001")[0]["grade_id"], 0)
  294. # ------------------------------------------------------------ 删除会员
  295. print("\n[删除会员]")
  296. execute("""insert into yoshop_user_oauth (user_id,oauth_type,oauth_id,unionid,store_id,is_delete,
  297. create_time,update_time) values (%s,'TESTJ','oauth-test','',%s,0,0,0)""",
  298. (test_user, STORE_ID))
  299. res = post("/store/user/delete", {"userId": test_user})
  300. eq("返回成功", res.get("status"), 200)
  301. eq("文案", res.get("message"), "删除成功")
  302. eq("会员标记删除", query("select is_delete from yoshop_user where user_id=%s",
  303. (test_user,))[0]["is_delete"], 1)
  304. eq("三方绑定同步标记", query("select is_delete from yoshop_user_oauth where user_id=%s",
  305. (test_user,))[0]["is_delete"], 1)
  306. eq("重复删除被拦", post("/store/user/delete", {"userId": test_user}).get("status"), 500)
  307. # -------------------------------------------------------- 领取记录列表
  308. print("\n[领取记录] 造一条领取记录后读取")
  309. execute("""insert into yoshop_user_coupon
  310. (coupon_id,name,coupon_type,reduce_price,discount,min_price,expire_type,expire_day,
  311. start_time,end_time,apply_range,apply_range_config,`describe`,is_expire,is_use,
  312. user_id,store_id,create_time,update_time)
  313. values (10002,'TESTJ领取券',20,0.00,99,50.00,20,1,1790784000,1793462399,10,'[]','',
  314. 0,0,10001,%s,1792000000,1792000000)""", (STORE_ID,))
  315. uc = query("select user_coupon_id from yoshop_user_coupon where name='TESTJ领取券'")[0]["user_coupon_id"]
  316. res = get("/store/market.coupon/receive", {"page": 1, "couponName": "TESTJ领取券"})
  317. data = res["data"]["list"]
  318. eq("总数", data["total"], 1)
  319. row = data["data"][0]
  320. eq("折扣率 9.9", row["discount"], 9.9)
  321. eq("开始时间 Y/m/d", row["start_time"], "2026/10/01")
  322. eq("state 正常", row["state"], {"text": "正常", "value": 1})
  323. check("带会员信息", isinstance(row.get("user"), dict) and row["user"]["user_id"] == 10001)
  324. check("会员含头像键", "avatar" in row["user"] and "avatar_url" in row["user"])
  325. check("会员无 grade 键", "grade" not in row["user"])
  326. res = get("/store/market.coupon/receive", {"page": 1, "nickName": "185****1340"})
  327. check("按昵称可检索", res["data"]["list"]["total"] >= 1)
  328. res = get("/store/market.coupon/receive", {"page": 1, "nickName": "不存在的昵称XYZ"})
  329. eq("昵称无匹配为空", res["data"]["list"]["total"], 0)
  330. finally:
  331. # ------------------------------------------------------------ 清理
  332. # 只删本次新建的记录(本地存在与线上对照的种子数据,不能按名称前缀删)
  333. print("\n[清理]")
  334. if coupon_ids:
  335. execute("delete from yoshop_coupon where coupon_id in (%s)"
  336. % ",".join(str(int(i)) for i in coupon_ids))
  337. if plan_ids:
  338. execute("delete from yoshop_recharge_plan where plan_id in (%s)"
  339. % ",".join(str(int(i)) for i in plan_ids))
  340. if grade_ids:
  341. execute("delete from yoshop_user_grade where grade_id in (%s)"
  342. % ",".join(str(int(i)) for i in grade_ids))
  343. execute("delete from yoshop_user_coupon where name='TESTJ领取券'")
  344. execute("delete from yoshop_user_balance_log where log_id>%s", (max_balance_log,))
  345. execute("delete from yoshop_user_points_log where log_id>%s", (max_points_log,))
  346. execute("delete from yoshop_user_grade_log where log_id>%s", (max_grade_log,))
  347. execute("delete from yoshop_user_oauth where user_id=%s", (test_user,))
  348. execute("delete from yoshop_user where user_id=%s", (test_user,))
  349. execute("update yoshop_user set balance=%s, points=%s, grade_id=%s where user_id=10001",
  350. (base_balance, base["points"], base["grade_id"]))
  351. restored = query("select balance, points, grade_id from yoshop_user where user_id=10001")[0]
  352. eq("余额已恢复", str(restored["balance"]), str(base_balance))
  353. eq("积分已恢复", restored["points"], base["points"])
  354. eq("等级已恢复", restored["grade_id"], base["grade_id"])
  355. print(f"\n通过 {PASS} / 失败 {FAIL}")
  356. if FAILS:
  357. print("失败项:" + "、".join(FAILS))
  358. if __name__ == "__main__":
  359. main()