test_order_writes.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. # -*- coding: utf-8 -*-
  2. """订单链路写接口端到端自测(订单事件 / 发货 / 售后)。
  3. 策略:本地库现状 + 现场造订单/售后单 → 调 Java 接口 → 直接查库断言落库结果 → 清理恢复。
  4. 写接口无法用线上 PHP 读回校验(本地库与线上是 PHP→本地单向同步),因此以库内断言为准。
  5. 用法:python test_order_writes.py
  6. 前置:python tools/backup_order_tables.py
  7. """
  8. import json
  9. import re
  10. import time
  11. from pathlib import Path
  12. import pymysql
  13. import requests
  14. from _root import ROOT
  15. JAVA_BASE = "http://127.0.0.1:18080"
  16. TOKEN = "testsession123"
  17. STORE_ID = 10001
  18. YML = Path(str(ROOT / "yoshop-java/src/main/resources/application.yml"))
  19. SESSION = requests.Session()
  20. SESSION.trust_env = False
  21. passed = failed = 0
  22. created = {"order_ids": [], "delivery_ids": [], "refund_ids": []}
  23. def check(name, cond, extra=""):
  24. global passed, failed
  25. if cond:
  26. passed += 1
  27. print(f" [ok] {name}")
  28. else:
  29. failed += 1
  30. print(f" [FAIL] {name} {extra}")
  31. def db():
  32. pwd = re.findall(r"password:\s*(.+)", YML.read_text(encoding="utf-8"))[0].strip().strip('"')
  33. return pymysql.connect(host="192.168.1.177", port=3306, user="root", password=pwd,
  34. database="shop", charset="utf8mb4", autocommit=True,
  35. cursorclass=pymysql.cursors.DictCursor)
  36. def java(path, method="get", params=None, body=None):
  37. url = JAVA_BASE + path
  38. headers = {"Access-Token": TOKEN}
  39. if method == "get":
  40. r = SESSION.get(url, headers=headers, params=params or {}, timeout=60)
  41. else:
  42. r = SESSION.post(url, headers=headers, json=body, timeout=60)
  43. try:
  44. return r.json()
  45. except Exception:
  46. return {"status": -1, "message": r.text[:200], "data": None}
  47. def one(cur, sql, args=None):
  48. cur.execute(sql, args or ())
  49. return cur.fetchone()
  50. def dec(value):
  51. return float(value) if value is not None else None
  52. def now():
  53. return int(time.time())
  54. # ---------------------------------------------------------------- 造数 / 清理
  55. def create_order(cur, items):
  56. """items: [(goods_sku_id, total_num, goods_price)],返回 (order_id, [order_goods_id...])"""
  57. order_no = "TESTJ%d" % int(time.time() * 1000)
  58. total = sum(round(p * n, 2) for _, n, p in items)
  59. cur.execute(
  60. "insert into yoshop_order (order_no,order_type,total_price,order_price,coupon_id,coupon_money,"
  61. "points_money,points_num,pay_price,update_price,buyer_remark,pay_method,pay_status,pay_time,"
  62. "trade_id,delivery_type,express_price,delivery_status,delivery_time,sync_weixin_shipping,"
  63. "receipt_status,receipt_time,order_status,points_bonus,merchant_remark,is_settled,settled_time,"
  64. "is_comment,order_source,order_source_id,order_source_data,platform,user_id,is_delete,store_id,"
  65. "create_time,update_time) values "
  66. "(%s,10,%s,%s,0,0,0,0,%s,0,'','balance',20,%s,0,10,0,10,0,0,10,0,10,0,'',0,0,0,10,0,'',"
  67. "'H5',10001,0,10001,%s,%s)",
  68. (order_no, total, total, total, now() - 60, now() - 60, now() - 60))
  69. order_id = cur.lastrowid
  70. created["order_ids"].append(order_id)
  71. goods_ids = []
  72. for sku_id, num, price in items:
  73. cur.execute(
  74. "insert into yoshop_order_goods (goods_id,goods_type,goods_name,image_id,deduct_stock_type,"
  75. "spec_type,goods_sku_id,goods_props,content,goods_no,goods_price,line_price,goods_weight,"
  76. "is_user_grade,grade_ratio,grade_goods_price,grade_total_money,coupon_money,points_money,"
  77. "points_num,points_bonus,total_num,total_price,total_pay_price,delivery_status,delivery_num,"
  78. "is_comment,order_id,user_id,goods_source_id,store_id,create_time) values "
  79. "(10004,10,'测试商品-百香果',10012,10,20,%s,'','','',%s,%s,1.5,0,0,0,0,0,0,0,0,%s,%s,%s,"
  80. "10,0,0,%s,10001,0,10001,%s)",
  81. (sku_id, price, price, num, round(price * num, 2), round(price * num, 2), order_id, now() - 60))
  82. goods_ids.append(cur.lastrowid)
  83. # 收货地址
  84. cur.execute(
  85. "insert into yoshop_order_address (name,phone,province_id,city_id,region_id,detail,order_id,"
  86. "user_id,store_id,create_time) values ('测试收货人','13700000000',1,2,3,'测试路1号',%s,10001,10001,%s)",
  87. (order_id, now() - 60))
  88. return order_id, goods_ids
  89. def create_refund(cur, order_id, order_goods_id, refund_type=10):
  90. cur.execute(
  91. "insert into yoshop_order_refund (order_id,order_goods_id,user_id,type,apply_desc,audit_status,"
  92. "refuse_desc,refund_money,is_user_send,send_time,express_id,express_no,is_receipt,status,"
  93. "store_id,create_time,update_time) values "
  94. "(%s,%s,10001,%s,'测试售后原因',0,'',0,0,0,'','',0,0,10001,%s,%s)",
  95. (order_id, order_goods_id, refund_type, now() - 30, now() - 30))
  96. refund_id = cur.lastrowid
  97. created["refund_ids"].append(refund_id)
  98. return refund_id
  99. def cleanup(cur, base_balance):
  100. for refund_id in created["refund_ids"]:
  101. cur.execute("delete from yoshop_order_refund where order_refund_id=%s", (refund_id,))
  102. cur.execute("delete from yoshop_order_refund_address where order_refund_id=%s", (refund_id,))
  103. for order_id in created["order_ids"]:
  104. cur.execute("delete from yoshop_order_delivery where order_id=%s", (order_id,))
  105. cur.execute("delete from yoshop_order_delivery_goods where order_id=%s", (order_id,))
  106. cur.execute("delete from yoshop_order_goods where order_id=%s", (order_id,))
  107. cur.execute("delete from yoshop_order_address where order_id=%s", (order_id,))
  108. cur.execute("delete from yoshop_order where order_id=%s", (order_id,))
  109. # 清理测试产生的余额流水(describe 带 TESTJ 订单号或标记)
  110. cur.execute("delete from yoshop_user_balance_log where `describe` like '%%TESTJ%%'")
  111. cur.execute("delete from yoshop_user_points_log where `describe` like '%%TESTJ%%'")
  112. cur.execute("update yoshop_user set balance=%s where user_id=10001", (base_balance,))
  113. # ---------------------------------------------------------------- 用例
  114. def case_update_price(cur):
  115. print("\n== 改价 / 备注 / 改地址 / 删除(订单 10002)")
  116. before = one(cur, "select * from yoshop_order where order_id=10002")
  117. base_price = dec(before["order_price"])
  118. r = java("/store/order.event/updatePrice", "post",
  119. body={"orderId": 10002, "form": {"order_price": 100, "express_price": 5}})
  120. check("改价返回成功", r.get("status") == 200 and r.get("message") == "操作成功", r)
  121. row = one(cur, "select * from yoshop_order where order_id=10002")
  122. check("order_price=100.00", dec(row["order_price"]) == 100.0, row["order_price"])
  123. check("express_price=5.00", dec(row["express_price"]) == 5.0, row["express_price"])
  124. check("pay_price=105.00", dec(row["pay_price"]) == 105.0, row["pay_price"])
  125. check("update_price=100-原价", round(dec(row["update_price"]), 2) == round(100 - base_price, 2),
  126. f'{row["update_price"]} 期望 {round(100 - base_price, 2)}')
  127. r = java("/store/order.event/updatePrice", "post",
  128. body={"orderId": 10001, "form": {"order_price": 10, "express_price": 0}})
  129. check("已支付订单改价被拒", r.get("status") == 500 and r.get("message") == "该订单不合法", r)
  130. r = java("/store/order.event/updatePrice", "post",
  131. body={"orderId": 10002, "form": {"order_price": 0, "express_price": 0}})
  132. check("实付款为 0 被拒", r.get("status") == 500 and r.get("message") == "订单实付款价格不能为0.00元", r)
  133. # 备注
  134. r = java("/store/order.event/updateRemark", "post",
  135. body={"orderId": 10002, "form": {"content": "测试商家备注888"}})
  136. check("备注返回成功", r.get("status") == 200, r)
  137. row = one(cur, "select merchant_remark from yoshop_order where order_id=10002")
  138. check("merchant_remark 落库", row["merchant_remark"] == "测试商家备注888", row)
  139. r = java("/store/order.event/updateRemark", "post", body={"orderId": 10002, "form": {}})
  140. row = one(cur, "select merchant_remark from yoshop_order where order_id=10002")
  141. check("空备注写为空串", row["merchant_remark"] == "", row)
  142. # 改地址
  143. r = java("/store/order.event/updateAddress", "post",
  144. body={"orderId": 10002,
  145. "form": {"name": "新收货人", "phone": "13611112222",
  146. "cascader": [310000, 310100, 310101], "detail": "新地址88号"}})
  147. check("改地址返回成功", r.get("status") == 200, r)
  148. addr = one(cur, "select * from yoshop_order_address where order_id=10002")
  149. check("收货人已更新", addr["name"] == "新收货人", addr)
  150. check("省市区已更新", (addr["province_id"], addr["city_id"], addr["region_id"]) == (310000, 310100, 310101), addr)
  151. check("详细地址已更新", addr["detail"] == "新地址88号", addr)
  152. # 恢复订单 10002 原值
  153. cur.execute("update yoshop_order set order_price=%s,pay_price=%s,update_price=%s,express_price=%s,"
  154. "merchant_remark=%s where order_id=10002",
  155. (before["order_price"], before["pay_price"], before["update_price"],
  156. before["express_price"], before["merchant_remark"]))
  157. cur.execute("update yoshop_order_address set name=%s,phone=%s,province_id=%s,city_id=%s,region_id=%s,"
  158. "detail=%s where order_id=10002",
  159. ("檀先生", "18587721340", 1, 2, 3, "长安大街111号"))
  160. def case_delete(cur):
  161. print("\n== 软删除(订单 10002)")
  162. r = java("/store/order.event/delete", "post", body={"orderId": 10002})
  163. check("删除返回成功", r.get("status") == 200 and r.get("message") == "删除成功", r)
  164. row = one(cur, "select is_delete from yoshop_order where order_id=10002")
  165. check("is_delete=1", row["is_delete"] == 1, row)
  166. r = java("/store/order/detail", "get", params={"orderId": 10002})
  167. check("删除后详情不可见", r.get("status") == 500 and r.get("message") == "未找到该订单记录", r)
  168. r = java("/store/order/list", "get", params={"dataType": "all", "page": 1})
  169. ids = [o["order_id"] for o in r["data"]["list"]["data"]]
  170. check("删除后列表不含该订单", 10002 not in ids, ids)
  171. cur.execute("update yoshop_order set is_delete=0 where order_id=10002")
  172. row = one(cur, "select is_delete from yoshop_order where order_id=10002")
  173. check("已恢复未删除状态", row["is_delete"] == 0, row)
  174. def case_confirm_cancel(cur):
  175. print("\n== 审核取消(订单 10001,余额支付)")
  176. base_user = one(cur, "select balance,points from yoshop_user where user_id=10001")
  177. base_stock = one(cur, "select stock_total from yoshop_goods where goods_id=10004")["stock_total"]
  178. base_sku = one(cur, "select stock_num from yoshop_goods_sku where goods_id=10004 and goods_sku_id='10001'")["stock_num"]
  179. # 拒绝取消:订单回到进行中,不退款
  180. cur.execute("update yoshop_order set order_status=21 where order_id=10001")
  181. r = java("/store/order.event/confirmCancel", "post",
  182. body={"orderId": 10001, "form": {"status": 0}})
  183. check("拒绝取消返回成功", r.get("status") == 200, r)
  184. row = one(cur, "select order_status from yoshop_order where order_id=10001")
  185. check("拒绝后 order_status=10", row["order_status"] == 10, row)
  186. user = one(cur, "select balance from yoshop_user where user_id=10001")
  187. check("拒绝取消不动余额", dec(user["balance"]) == dec(base_user["balance"]), user)
  188. # 同意取消:退款 + 取消事件
  189. cur.execute("update yoshop_order set order_status=21 where order_id=10001")
  190. r = java("/store/order.event/confirmCancel", "post",
  191. body={"orderId": 10001, "form": {"status": 1}})
  192. check("同意取消返回成功", r.get("status") == 200, r)
  193. row = one(cur, "select order_status from yoshop_order where order_id=10001")
  194. check("同意后 order_status=20", row["order_status"] == 20, row)
  195. user = one(cur, "select balance from yoshop_user where user_id=10001")
  196. check("余额已退回 31 元", round(dec(user["balance"]) - dec(base_user["balance"]), 2) == 31.0,
  197. f'{base_user["balance"]} -> {user["balance"]}')
  198. log = one(cur, "select * from yoshop_user_balance_log where scene=40 order by log_id desc limit 1")
  199. check("写入退款流水 scene=40", log is not None and dec(log["money"]) == 31.0, log)
  200. check("流水描述含订单号", log is not None and "369583349062174103" in (log["describe"] or ""), log)
  201. stock = one(cur, "select stock_total from yoshop_goods where goods_id=10004")["stock_total"]
  202. sku = one(cur, "select stock_num from yoshop_goods_sku where goods_id=10004 and goods_sku_id='10001'")["stock_num"]
  203. check("商品总库存已回退 +1", stock == base_stock + 1, f"{base_stock} -> {stock}")
  204. check("SKU 库存已回退 +1", sku == base_sku + 1, f"{base_sku} -> {sku}")
  205. # 恢复
  206. cur.execute("update yoshop_order set order_status=10 where order_id=10001")
  207. cur.execute("update yoshop_user set balance=%s where user_id=10001", (base_user["balance"],))
  208. cur.execute("update yoshop_goods set stock_total=%s where goods_id=10004", (base_stock,))
  209. cur.execute("update yoshop_goods_sku set stock_num=%s where goods_id=10004 and goods_sku_id='10001'", (base_sku,))
  210. cur.execute("delete from yoshop_user_balance_log where scene=40")
  211. def case_delivery(cur):
  212. print("\n== 发货(新建订单)")
  213. order_id, goods_ids = create_order(cur, [("10001", 2, 28.00), ("10002", 1, 28.00)])
  214. print(f" 测试订单 order_id={order_id} goods={goods_ids}")
  215. # 部分发货
  216. r = java("/store/order.delivery/delivery", "post",
  217. body={"orderId": order_id,
  218. "form": {"deliveryMethod": 10, "expressId": 10003, "expressNo": "TEST123456",
  219. "isAllPack": False,
  220. "packGoodsData": [{"orderGoodsId": goods_ids[0], "deliveryNum": 1}]}})
  221. check("部分发货返回成功", r.get("status") == 200 and r.get("message") == "发货成功", r)
  222. dl = one(cur, "select * from yoshop_order_delivery where order_id=%s order by delivery_id desc limit 1", (order_id,))
  223. check("发货单已写入", dl is not None and dl["express_no"] == "TEST123456", dl)
  224. check("发货方式=10", dl is not None and dl["delivery_method"] == 10, dl)
  225. check("发货单 store_id=10001", dl is not None and dl["store_id"] == STORE_ID, dl)
  226. dg = one(cur, "select * from yoshop_order_delivery_goods where delivery_id=%s", (dl["delivery_id"],))
  227. check("发货商品写入", dg is not None and dg["delivery_num"] == 1 and dg["goods_id"] == 10004, dg)
  228. g1 = one(cur, "select delivery_num,delivery_status from yoshop_order_goods where order_goods_id=%s", (goods_ids[0],))
  229. check("订单商品已发 1 件/部分发货", (g1["delivery_num"], g1["delivery_status"]) == (1, 30), g1)
  230. g2 = one(cur, "select delivery_num,delivery_status from yoshop_order_goods where order_goods_id=%s", (goods_ids[1],))
  231. check("未发商品状态不变", (g2["delivery_num"], g2["delivery_status"]) == (0, 10), g2)
  232. order = one(cur, "select delivery_status,delivery_time from yoshop_order where order_id=%s", (order_id,))
  233. check("订单=部分发货(30)", order["delivery_status"] == 30, order)
  234. check("订单发货时间已写", order["delivery_time"] > 0, order)
  235. # 整单发货 + 无需物流
  236. r = java("/store/order.delivery/delivery", "post",
  237. body={"orderId": order_id,
  238. "form": {"deliveryMethod": 20, "isAllPack": True}})
  239. check("整单发货返回成功", r.get("status") == 200, r)
  240. dl2 = one(cur, "select * from yoshop_order_delivery where order_id=%s order by delivery_id desc limit 1", (order_id,))
  241. check("无需物流时单号为空", dl2["express_no"] == "", dl2)
  242. check("发货方式=20", dl2["delivery_method"] == 20, dl2)
  243. g1 = one(cur, "select delivery_num,delivery_status from yoshop_order_goods where order_goods_id=%s", (goods_ids[0],))
  244. check("商品1全部发完", (g1["delivery_num"], g1["delivery_status"]) == (2, 20), g1)
  245. g2 = one(cur, "select delivery_num,delivery_status from yoshop_order_goods where order_goods_id=%s", (goods_ids[1],))
  246. check("商品2整单发完", (g2["delivery_num"], g2["delivery_status"]) == (1, 20), g2)
  247. order = one(cur, "select delivery_status from yoshop_order where order_id=%s", (order_id,))
  248. check("订单=已发货(20)", order["delivery_status"] == 20, order)
  249. # 重复发货
  250. r = java("/store/order.delivery/delivery", "post",
  251. body={"orderId": order_id, "form": {"deliveryMethod": 10, "isAllPack": True}})
  252. check("已发货订单再次发货被拒", r.get("status") == 500 and "不满足发货条件" in (r.get("message") or ""), r)
  253. # 未支付订单发货
  254. r = java("/store/order.delivery/delivery", "post",
  255. body={"orderId": 10002, "form": {"deliveryMethod": 10, "isAllPack": True}})
  256. check("未支付订单发货被拒", r.get("status") == 500 and "不满足发货条件" in (r.get("message") or ""), r)
  257. # 发货记录列表能查到新发货单
  258. r = java("/store/order.delivery/list", "get", params={"page": 1})
  259. found = [d for d in r["data"]["list"]["data"] if d["order_id"] == order_id]
  260. check("发货列表含新发货单", len(found) >= 1, r["data"]["list"]["total"])
  261. if found:
  262. item = found[0]
  263. check("列表含 orderData/orderData.user", "orderData" in item and item["orderData"].get("user") is not None, list(item.keys()))
  264. check("列表 goods 含订单商品", item["goods"] and item["goods"][0].get("goods") is not None, item.get("goods"))
  265. check("列表含物流公司", item.get("express") is not None and item["express"]["express_name"] == "圆通速递", item.get("express"))
  266. check("列表不含 eorder_html", "eorder_html" not in item, list(item.keys()))
  267. # 详情
  268. dl_id = found[0]["delivery_id"] if found else dl2["delivery_id"]
  269. r = java("/store/order.delivery/detail", "get", params={"deliveryId": dl_id})
  270. det = r.get("data", {}).get("detail") or {}
  271. check("发货单详情含 eorder_html", "eorder_html" in det, list(det.keys()))
  272. check("发货单详情无关联键", "goods" not in det and "orderData" not in det, list(det.keys()))
  273. return order_id, goods_ids
  274. def case_refund(cur, order_id, goods_ids):
  275. print("\n== 售后(审核 / 确认收货退款)")
  276. base_user = one(cur, "select balance from yoshop_user where user_id=10001")
  277. refund_id = create_refund(cur, order_id, goods_ids[0], refund_type=10)
  278. # 拒绝无原因
  279. r = java("/store/order.refund/audit", "post",
  280. body={"orderRefundId": refund_id, "form": {"audit_status": 20}})
  281. check("拒绝未填原因被拦", r.get("status") == 500 and r.get("message") == "请输入拒绝原因", r)
  282. # 同意无地址
  283. r = java("/store/order.refund/audit", "post",
  284. body={"orderRefundId": refund_id, "form": {"audit_status": 10}})
  285. check("同意未选地址被拦", r.get("status") == 500 and r.get("message") == "请选择退货地址", r)
  286. # 同意 + 退货地址
  287. r = java("/store/order.refund/audit", "post",
  288. body={"orderRefundId": refund_id, "form": {"audit_status": 10, "address_id": 10001}})
  289. check("同意售后返回成功", r.get("status") == 200, r)
  290. row = one(cur, "select * from yoshop_order_refund where order_refund_id=%s", (refund_id,))
  291. check("audit_status=10", row["audit_status"] == 10, row)
  292. check("退货退款单仍为进行中", row["status"] == 0, row)
  293. addr = one(cur, "select * from yoshop_order_refund_address where order_refund_id=%s", (refund_id,))
  294. check("退货地址已写入", addr is not None and addr["name"] == "仓库", addr)
  295. check("退货地址 region_id 来自商城地址", addr is not None and addr["region_id"] == 5, addr)
  296. # 退款金额超限
  297. r = java("/store/order.refund/receipt", "post",
  298. body={"orderRefundId": refund_id, "form": {"refund_money": 9999}})
  299. check("超额退款被拦", r.get("status") == 500 and r.get("message") == "退款金额不能大于商品实付款金额", r)
  300. # 正常收货退款
  301. r = java("/store/order.refund/receipt", "post",
  302. body={"orderRefundId": refund_id, "form": {"refund_money": 10}})
  303. check("确认收货退款成功", r.get("status") == 200, r)
  304. row = one(cur, "select * from yoshop_order_refund where order_refund_id=%s", (refund_id,))
  305. check("refund_money=10.00", dec(row["refund_money"]) == 10.0, row)
  306. check("is_receipt=1", row["is_receipt"] == 1, row)
  307. check("status=20 已完成", row["status"] == 20, row)
  308. user = one(cur, "select balance from yoshop_user where user_id=10001")
  309. check("余额增加 10 元", round(dec(user["balance"]) - dec(base_user["balance"]), 2) == 10.0,
  310. f'{base_user["balance"]} -> {user["balance"]}')
  311. log = one(cur, "select * from yoshop_user_balance_log where scene=40 order by log_id desc limit 1")
  312. check("退款流水已写入", log is not None and dec(log["money"]) == 10.0, log)
  313. # 换货:同意即完成
  314. exch = create_refund(cur, order_id, goods_ids[1], refund_type=20)
  315. r = java("/store/order.refund/audit", "post",
  316. body={"orderRefundId": exch, "form": {"audit_status": 10, "address_id": 10001}})
  317. row = one(cur, "select * from yoshop_order_refund where order_refund_id=%s", (exch,))
  318. check("换货同意后直接完成", r.get("status") == 200 and row["status"] == 20, row)
  319. # 拒绝
  320. rej = create_refund(cur, order_id, goods_ids[1], refund_type=10)
  321. r = java("/store/order.refund/audit", "post",
  322. body={"orderRefundId": rej, "form": {"audit_status": 20, "refuse_desc": "不符合退货条件"}})
  323. row = one(cur, "select * from yoshop_order_refund where order_refund_id=%s", (rej,))
  324. check("拒绝售后 status=10", r.get("status") == 200 and row["status"] == 10, row)
  325. check("拒绝原因已落库", row["refuse_desc"] == "不符合退货条件", row)
  326. check("拒绝不写退货地址",
  327. one(cur, "select id from yoshop_order_refund_address where order_refund_id=%s", (rej,)) is None)
  328. # 列表 / 详情读回
  329. r = java("/store/order.refund/list", "get", params={"page": 1})
  330. rows = [x for x in r["data"]["list"]["data"] if x["order_refund_id"] == refund_id]
  331. check("售后列表能查到该单", len(rows) == 1, r["data"]["list"]["total"])
  332. if rows:
  333. item = rows[0]
  334. check("列表含订单号", item.get("order_no") is not None, item.get("order_no"))
  335. check("列表含 orderGoods.orderData.user",
  336. item.get("orderGoods") is not None and item.get("orderData") is not None and item.get("user") is not None,
  337. list(item.keys()))
  338. r = java("/store/order.refund/detail", "get", params={"orderRefundId": refund_id})
  339. det = r.get("data", {}).get("detail") or {}
  340. check("详情含 images/address/orderGoods",
  341. all(k in det for k in ("images", "address", "orderGoods", "orderData", "user", "express")), list(det.keys()))
  342. check("详情退货地址含 region", det.get("address") and "region" in det["address"], det.get("address"))
  343. check("详情不含 order_no", "order_no" not in det, list(det.keys()))
  344. cur.execute("update yoshop_user set balance=%s where user_id=10001", (base_user["balance"],))
  345. def main():
  346. cur = db().cursor()
  347. base_balance = one(cur, "select balance from yoshop_user where user_id=10001")["balance"]
  348. try:
  349. case_update_price(cur)
  350. case_delete(cur)
  351. case_confirm_cancel(cur)
  352. order_id, goods_ids = case_delivery(cur)
  353. case_refund(cur, order_id, goods_ids)
  354. finally:
  355. cleanup(cur, base_balance)
  356. print("\n已清理测试数据")
  357. print(f"\n通过 {passed} / 失败 {failed}")
  358. if __name__ == "__main__":
  359. main()