巴青农资商城

test_seller_flow.py 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. # ============================================================
  2. # 商家端 — 全量端到端测试
  3. # 覆盖 24 个 Controller,约 90 个 API 端点
  4. # ============================================================
  5. import pytest
  6. import json
  7. import random
  8. from api_client import ApiClient
  9. from config import SELLER_SHOP_ID
  10. # ============================================================
  11. # 商家 — 店铺切换 (SellerShopContextController)
  12. # ============================================================
  13. class TestSellerContext:
  14. def test_80_switch_shop(self, client, seller_token):
  15. """切换店铺上下文"""
  16. resp = client.put("/agri/seller/context/shop", json={
  17. "shopId": SELLER_SHOP_ID
  18. })
  19. client.assert_ok("切换店铺失败")
  20. print(f" [OK] 切换店铺 shopId={SELLER_SHOP_ID}")
  21. # ============================================================
  22. # 商家 — 员工管理 (MerchantEmployeeController)
  23. # ============================================================
  24. class TestSellerEmployee:
  25. def test_81_employee_list(self, client, seller_token):
  26. """员工列表"""
  27. resp = client.get("/agri/seller/employee/list")
  28. client.assert_ok("查询员工列表失败")
  29. data = client.extract_data() or {}
  30. print(f" [OK] 员工列表 total={data.get('total','?')}")
  31. def test_82_employee_quota(self, client, seller_token):
  32. """员工名额配额"""
  33. resp = client.get("/agri/seller/employee/quota")
  34. client.assert_ok("查询员工配额失败")
  35. quota = client.extract_data() or {}
  36. print(f" [OK] 员工配额: {quota}")
  37. def test_83_employee_role_options(self, client, seller_token):
  38. """员工角色选项"""
  39. resp = client.get("/agri/seller/employee/roleOptions")
  40. client.assert_ok("查询角色选项失败")
  41. roles = client.extract_data() or []
  42. print(f" [OK] 员工角色选项 count={len(roles) if isinstance(roles, list) else 0}")
  43. # ============================================================
  44. # 商家 — 角色管理 (MerchantRoleController)
  45. # ============================================================
  46. class TestSellerRole:
  47. def test_84_role_list(self, client, seller_token):
  48. """角色列表"""
  49. resp = client.get("/agri/seller/role/list")
  50. client.assert_ok("查询角色列表失败")
  51. data = client.extract_data() or {}
  52. print(f" [OK] 角色列表 total={data.get('total','?')}")
  53. def test_85_role_menu_tree(self, client, seller_token):
  54. """角色菜单树"""
  55. resp = client.get("/agri/seller/role/menuTree")
  56. client.assert_ok("查询菜单树失败")
  57. tree = client.extract_data() or []
  58. print(f" [OK] 角色菜单树 nodes={len(tree)}")
  59. # ============================================================
  60. # 商家 — 商品管理 (SellerGoodsController)
  61. # ============================================================
  62. class TestSellerGoods:
  63. def test_86_goods_list(self, client, seller_token):
  64. """商家商品列表"""
  65. resp = client.get("/agri/seller/goods/list")
  66. client.assert_ok("查询商品列表失败")
  67. data = client.extract_data() or {}
  68. total = data.get("total", 0) if isinstance(data, dict) else 0
  69. print(f" [OK] 商家商品列表 total={total}")
  70. def test_87_goods_category_options(self, client, seller_token):
  71. """商品分类选项"""
  72. resp = client.get("/agri/seller/goods/categoryOptions")
  73. client.assert_ok("查询分类选项失败")
  74. cats = client.extract_data() or []
  75. print(f" [OK] 分类选项 count={len(cats)}")
  76. if cats:
  77. client._test_seller_category_id = cats[0].get("categoryId") or cats[0].get("id")
  78. def test_88_goods_service_options(self, client, seller_token):
  79. """商品服务选项"""
  80. resp = client.get("/agri/seller/goods/serviceOptions")
  81. client.assert_ok("查询服务选项失败")
  82. svc = client.extract_data() or {}
  83. print(f" [OK] 服务选项: {json.dumps(svc, ensure_ascii=False)[:100]}")
  84. def test_89_goods_attr_template_options(self, client, seller_token):
  85. """属性模板选项"""
  86. resp = client.get("/agri/seller/goods/attrTemplateOptions")
  87. client.assert_ok("查询属性模板失败")
  88. tmpl = client.extract_data() or []
  89. print(f" [OK] 属性模板选项 count={len(tmpl) if isinstance(tmpl, list) else 0}")
  90. def test_90_goods_freight_options(self, client, seller_token):
  91. """运费模板选项"""
  92. resp = client.get("/agri/seller/goods/freightTemplateOptions")
  93. client.assert_ok("查询运费模板失败")
  94. tmpl = client.extract_data() or []
  95. print(f" [OK] 运费模板选项 count={len(tmpl)}")
  96. if tmpl:
  97. client._test_seller_freight_id = tmpl[0].get("templateId") or tmpl[0].get("id")
  98. def test_91_goods_freight_default(self, client, seller_token):
  99. """默认运费模板"""
  100. resp = client.get("/agri/seller/goods/freightDefault")
  101. client.assert_ok("查询默认运费模板失败")
  102. default = client.extract_data() or {}
  103. print(f" [OK] 默认运费: {json.dumps(default, ensure_ascii=False)[:80]}")
  104. def test_92_goods_shop_category_options(self, client, seller_token):
  105. """店铺商品分类选项"""
  106. resp = client.get("/agri/seller/goods/shopCategoryOptions", params={"visibleOnly": True})
  107. client.assert_ok("查询店铺分类选项失败")
  108. cats = client.extract_data() or []
  109. print(f" [OK] 店铺分类选项 count={len(cats) if isinstance(cats, list) else 0}")
  110. def test_93_goods_detail(self, client, seller_token):
  111. """商家商品详情"""
  112. resp = client.get("/agri/seller/goods/list", params={"pageSize": 1})
  113. data = client.assert_ok()
  114. rows = (data.get("data") or {}).get("rows") or []
  115. if not rows:
  116. pytest.skip("无商品数据")
  117. gid = rows[0].get("goodsId")
  118. resp = client.get(f"/agri/seller/goods/{gid}")
  119. client.assert_ok("查询商品详情失败")
  120. print(f" [OK] 商家商品详情 goodsId={gid}")
  121. # ============================================================
  122. # 商家 — 订单管理 (SellerOrderController)
  123. # ============================================================
  124. class TestSellerOrder:
  125. def test_94_seller_order_list(self, client, seller_token):
  126. """商家订单列表"""
  127. resp = client.get("/agri/seller/order/list")
  128. client.assert_ok("查询订单列表失败")
  129. data = client.extract_data() or {}
  130. total = data.get("total", 0) if isinstance(data, dict) else 0
  131. print(f" [OK] 商家订单列表 total={total}")
  132. def test_95_seller_order_detail(self, client, seller_token):
  133. """商家订单详情"""
  134. resp = client.get("/agri/seller/order/list", params={"pageSize": 1})
  135. data = client.assert_ok()
  136. rows = (data.get("data") or {}).get("rows") or []
  137. if not rows:
  138. pytest.skip("无订单数据")
  139. oid = rows[0].get("orderId")
  140. resp = client.get(f"/agri/seller/order/{oid}")
  141. client.assert_ok("查询订单详情失败")
  142. print(f" [OK] 商家订单详情 orderId={oid}")
  143. # ============================================================
  144. # 商家 — 发货管理 (SellerShipController)
  145. # ============================================================
  146. class TestSellerShip:
  147. def test_96_ship_badges(self, client, seller_token):
  148. """发货角标"""
  149. resp = client.get("/agri/seller/ship/badges")
  150. client.assert_ok("查询发货角标失败")
  151. badges = client.extract_data() or {}
  152. print(f" [OK] 发货角标: {badges}")
  153. def test_97_ship_list(self, client, seller_token):
  154. """发货列表"""
  155. resp = client.get("/agri/seller/ship/list")
  156. client.assert_ok("查询发货列表失败")
  157. data = client.extract_data() or {}
  158. total = data.get("total", 0) if isinstance(data, dict) else 0
  159. print(f" [OK] 发货列表 total={total}")
  160. def test_98_ship_detail(self, client, seller_token):
  161. """发货详情"""
  162. resp = client.get("/agri/seller/ship/list", params={"pageSize": 1})
  163. data = client.assert_ok()
  164. rows = (data.get("data") or {}).get("rows") or []
  165. if not rows:
  166. pytest.skip("无发货数据")
  167. oid = rows[0].get("orderId")
  168. resp = client.get(f"/agri/seller/ship/{oid}")
  169. client.assert_ok("查询发货详情失败")
  170. print(f" [OK] 发货详情 orderId={oid}")
  171. # ============================================================
  172. # 商家 — 售后管理 (SellerAftersaleController)
  173. # ============================================================
  174. class TestSellerAftersale:
  175. def test_99_aftersale_list(self, client, seller_token):
  176. """售后列表"""
  177. resp = client.get("/agri/seller/aftersale/list")
  178. client.assert_ok("查询售后列表失败")
  179. data = client.extract_data() or {}
  180. total = data.get("total", 0) if isinstance(data, dict) else 0
  181. print(f" [OK] 售后列表 total={total}")
  182. def test_100_aftersale_detail(self, client, seller_token):
  183. """售后详情"""
  184. resp = client.get("/agri/seller/aftersale/list", params={"pageSize": 1})
  185. data = client.assert_ok()
  186. rows = (data.get("data") or {}).get("rows") or []
  187. if not rows:
  188. pytest.skip("无售后数据")
  189. aid = rows[0].get("aftersaleId")
  190. resp = client.get(f"/agri/seller/aftersale/{aid}")
  191. client.assert_ok("查询售后详情失败")
  192. print(f" [OK] 售后详情 aftersaleId={aid}")
  193. # ============================================================
  194. # 商家 — 评价管理 (SellerReviewController)
  195. # ============================================================
  196. class TestSellerReview:
  197. def test_101_review_list(self, client, seller_token):
  198. """评价列表"""
  199. resp = client.get("/agri/seller/review/list")
  200. client.assert_ok("查询评价列表失败")
  201. data = client.extract_data() or {}
  202. total = data.get("total", 0) if isinstance(data, dict) else 0
  203. print(f" [OK] 评价列表 total={total}")
  204. # ============================================================
  205. # 商家 — 运费模板 (SellerFreightTemplateController)
  206. # ============================================================
  207. class TestSellerFreight:
  208. def test_102_freight_template_list(self, client, seller_token):
  209. """运费模板列表"""
  210. resp = client.get("/agri/seller/freightTemplate/list")
  211. client.assert_ok("查询运费模板失败")
  212. data = client.extract_data() or {}
  213. total = data.get("total", 0) if isinstance(data, dict) else 0
  214. print(f" [OK] 运费模板列表 total={total}")
  215. def test_103_freight_template_detail(self, client, seller_token):
  216. """运费模板详情"""
  217. resp = client.get("/agri/seller/freightTemplate/list", params={"pageSize": 1})
  218. data = client.assert_ok()
  219. rows = (data.get("data") or {}).get("rows") or []
  220. if not rows:
  221. pytest.skip("无运费模板")
  222. tid = rows[0].get("templateId")
  223. resp = client.get(f"/agri/seller/freightTemplate/{tid}")
  224. client.assert_ok("查询运费模板详情失败")
  225. print(f" [OK] 运费模板详情 templateId={tid}")
  226. # ============================================================
  227. # 商家 — 属性模板 (SellerAttrTemplateController)
  228. # ============================================================
  229. class TestSellerAttrTemplate:
  230. def test_104_attr_template_list(self, client, seller_token):
  231. """属性模板列表"""
  232. resp = client.get("/agri/seller/attrTemplate/list")
  233. client.assert_ok("查询属性模板失败")
  234. data = client.extract_data() or {}
  235. total = data.get("total", 0) if isinstance(data, dict) else 0
  236. print(f" [OK] 属性模板列表 total={total}")
  237. def test_105_attr_template_detail(self, client, seller_token):
  238. """属性模板详情"""
  239. resp = client.get("/agri/seller/attrTemplate/list", params={"pageSize": 1})
  240. data = client.assert_ok()
  241. rows = (data.get("data") or {}).get("rows") or []
  242. if not rows:
  243. pytest.skip("无属性模板")
  244. tid = rows[0].get("templateId")
  245. resp = client.get(f"/agri/seller/attrTemplate/{tid}")
  246. client.assert_ok("查询属性模板详情失败")
  247. print(f" [OK] 属性模板详情 templateId={tid}")
  248. # ============================================================
  249. # 商家 — 分类管理 (SellerPlatformCategory + ShopGoodsCategory)
  250. # ============================================================
  251. class TestSellerCategory:
  252. def test_106_platform_category_options(self, client, seller_token):
  253. """平台分类选项"""
  254. resp = client.get("/agri/seller/category/platformLevel2Options")
  255. client.assert_ok("查询平台分类选项失败")
  256. cats = client.extract_data() or []
  257. print(f" [OK] 平台分类选项 count={len(cats) if isinstance(cats, list) else 0}")
  258. def test_107_shop_category_list(self, client, seller_token):
  259. """店铺分类列表"""
  260. resp = client.get("/agri/seller/shopCategory/list")
  261. client.assert_ok("查询店铺分类失败")
  262. data = client.extract_data() or {}
  263. print(f" [OK] 店铺分类列表正常")
  264. def test_108_shop_category_scope(self, client, seller_token):
  265. """店铺分类使用范围"""
  266. resp = client.get("/agri/seller/shopCategory/scope")
  267. client.assert_ok("查询店铺分类范围失败")
  268. scope = client.extract_data() or {}
  269. print(f" [OK] 店铺分类范围: {scope}")
  270. # ============================================================
  271. # 商家 — 店铺管理 (SellerShopController)
  272. # ============================================================
  273. class TestSellerShop:
  274. def test_109_shop_employee_stats(self, client, seller_token):
  275. """店铺员工统计"""
  276. resp = client.get("/agri/seller/shop/employeeStats")
  277. client.assert_ok("查询员工统计失败")
  278. stats = client.extract_data() or {}
  279. print(f" [OK] 员工统计: {stats}")
  280. # ============================================================
  281. # 商家 — 配送设置 (SellerDeliveryController)
  282. # ============================================================
  283. class TestSellerDelivery:
  284. def test_110_delivery_setting_get(self, client, seller_token):
  285. """配送设置查询"""
  286. resp = client.get("/agri/seller/delivery")
  287. client.assert_ok("查询配送设置失败")
  288. setting = client.extract_data() or {}
  289. print(f" [OK] 配送设置: {json.dumps(setting, ensure_ascii=False)[:100]}")
  290. # ============================================================
  291. # 商家 — 财务管理 (SellerFund / PayAccount / Withdraw)
  292. # ============================================================
  293. class TestSellerFinance:
  294. def test_111_fund_summary(self, client, seller_token):
  295. """资金概览"""
  296. resp = client.get("/agri/seller/finance/overview/summary")
  297. client.assert_ok("查询资金概览失败")
  298. summary = client.extract_data() or {}
  299. print(f" [OK] 商家资金概览: {json.dumps(summary, ensure_ascii=False)[:100]}")
  300. def test_112_fund_logs(self, client, seller_token):
  301. """资金流水"""
  302. resp = client.get("/agri/seller/finance/overview/logs")
  303. client.assert_ok("查询资金流水失败")
  304. data = client.extract_data() or {}
  305. total = data.get("total", 0) if isinstance(data, dict) else 0
  306. print(f" [OK] 资金流水 total={total}")
  307. def test_113_pay_account_list(self, client, seller_token):
  308. """收款账户列表"""
  309. resp = client.get("/agri/seller/finance/payAccount/list")
  310. client.assert_ok("查询收款账户失败")
  311. accounts = client.extract_data() or []
  312. print(f" [OK] 收款账户 count={len(accounts) if isinstance(accounts, list) else 0}")
  313. def test_114_pay_account_options(self, client, seller_token):
  314. """收款账户选项"""
  315. resp = client.get("/agri/seller/finance/payAccount/options")
  316. client.assert_ok("查询账户选项失败")
  317. opts = client.extract_data() or []
  318. print(f" [OK] 收款账户选项正常")
  319. def test_115_withdraw_balance(self, client, seller_token):
  320. """提现余额"""
  321. resp = client.get("/agri/seller/finance/withdraw/balance")
  322. client.assert_ok("查询提现余额失败")
  323. balance = client.extract_data() or {}
  324. print(f" [OK] 提现余额: {json.dumps(balance, ensure_ascii=False)[:80]}")
  325. def test_116_withdraw_list(self, client, seller_token):
  326. """提现记录"""
  327. resp = client.get("/agri/seller/finance/withdraw/list")
  328. client.assert_ok("查询提现记录失败")
  329. data = client.extract_data() or {}
  330. total = data.get("total", 0) if isinstance(data, dict) else 0
  331. print(f" [OK] 提现记录 total={total}")
  332. # ============================================================
  333. # 商家 — 库存管理 (5个StockController)
  334. # ============================================================
  335. class TestSellerStock:
  336. def test_117_stock_query_list(self, client, seller_token):
  337. """库存查询"""
  338. resp = client.get("/agri/seller/stock/query/list")
  339. client.assert_ok("查询库存失败")
  340. data = client.extract_data() or {}
  341. total = data.get("total", 0) if isinstance(data, dict) else 0
  342. print(f" [OK] 库存查询 total={total}")
  343. def test_118_stock_inbound_list(self, client, seller_token):
  344. """入库记录"""
  345. resp = client.get("/agri/seller/stock/inbound/list")
  346. client.assert_ok("查询入库记录失败")
  347. data = client.extract_data() or {}
  348. total = data.get("total", 0) if isinstance(data, dict) else 0
  349. print(f" [OK] 入库记录 total={total}")
  350. def test_119_stock_outbound_list(self, client, seller_token):
  351. """出库记录"""
  352. resp = client.get("/agri/seller/stock/outbound/list")
  353. client.assert_ok("查询出库记录失败")
  354. data = client.extract_data() or {}
  355. total = data.get("total", 0) if isinstance(data, dict) else 0
  356. print(f" [OK] 出库记录 total={total}")
  357. def test_120_stock_adjust_list(self, client, seller_token):
  358. """库存调整记录"""
  359. resp = client.get("/agri/seller/stock/adjust/list")
  360. client.assert_ok("查询库存调整失败")
  361. data = client.extract_data() or {}
  362. total = data.get("total", 0) if isinstance(data, dict) else 0
  363. print(f" [OK] 库存调整 total={total}")
  364. def test_121_stock_log_list(self, client, seller_token):
  365. """库存流水日志"""
  366. resp = client.get("/agri/seller/stock/log/list")
  367. client.assert_ok("查询库存日志失败")
  368. data = client.extract_data() or {}
  369. total = data.get("total", 0) if isinstance(data, dict) else 0
  370. print(f" [OK] 库存日志 total={total}")
  371. def test_122_stock_inbound_detail(self, client, seller_token):
  372. """入库详情"""
  373. resp = client.get("/agri/seller/stock/inbound/list", params={"pageSize": 1})
  374. data = client.assert_ok()
  375. rows = (data.get("data") or {}).get("rows") or []
  376. if not rows:
  377. pytest.skip("无入库记录")
  378. iid = rows[0].get("inboundId")
  379. resp = client.get(f"/agri/seller/stock/inbound/{iid}")
  380. client.assert_ok("查询入库详情失败")
  381. print(f" [OK] 入库详情 inboundId={iid}")
  382. def test_123_stock_goods_logs(self, client, seller_token):
  383. """商品库存流水"""
  384. resp = client.get("/agri/seller/stock/query/list", params={"pageSize": 1})
  385. data = client.assert_ok()
  386. rows = (data.get("data") or {}).get("rows") or []
  387. if not rows:
  388. pytest.skip("无库存数据")
  389. gid = rows[0].get("goodsId")
  390. resp = client.get(f"/agri/seller/stock/query/{gid}/logs")
  391. client.assert_ok("查询商品流水失败")
  392. print(f" [OK] 商品库存流水 goodsId={gid}")
  393. # ============================================================
  394. # 商家 — 微信支付配置 (SellerShopWechatPayController)
  395. # ============================================================
  396. class TestSellerWechat:
  397. def test_124_wechat_pay_get(self, client, seller_token):
  398. """商家微信支付配置"""
  399. resp = client.get("/agri/seller/wechat-pay")
  400. client.assert_ok("查询支付配置失败")
  401. config = client.extract_data() or {}
  402. print(f" [OK] 商家支付配置: {json.dumps(config, ensure_ascii=False)[:100]}")