test_order_writes.py 23 KB

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