"""跨端 E2E 测试 — 司机接单装货卸货 + 管理端核算打款完整流程。 业务流程: 司机 APP (Android): 1. 接单: 点击货源 → 选择货源单 → 填写数量 → 勾选协议 → 接单 2. 装货: 装货 → 取消弹窗 → 吨位 → 选图 → 相册 → 勾图 → 完成 → 勾选 → 装货确认 → 合同 → 已知晓 → 确定 3. 卸货: 卸货 → 取消弹窗 → 吨位 → 选图 → 相册 → 勾图 → 完成 → 卸货确认 → 确定 4. 获取运输单号 Web 管理端 (基础流程): 5. 运费核算: URL 跳转 → 输入单号 → 查询 →(无数据时 SQL 重试)→ 编辑 → 核算 6. 运单审核: URL 跳转 → 输入单号 → 查询 → 审核 → 滚动弹窗 → 审核通过 7. 垫资-财务打款: URL 跳转 → 输入单号 → 查询 → 在线支付 → 滚动 → 勾选光大 → 勾选手机号 → 获取验证码 → 输入验证码 → 确认打款 8. 垫资-货主打款: URL 跳转 → 输入单号 → 查询 → 打款 → 勾选光大 → 确认打款 → 确认弹窗 Web 管理端 (车队长全额收款流程): 5. 运费核算: URL 跳转 → 输入单号 → 查询 → 编辑 → 选择车队长 → 选择"车队长全额收款"模式 → 核算 6-8. 同基础流程 运行: pytest tests/cross_end/ -m cross_end -v -s 报告: allure serve output/allure-results 前置条件: - Appium server: http://localhost:4723 - Android 模拟器已启动,司机 APP 已安装并登录过一次 (noReset) - 管理端 auth 态: python tests/web/admin/save_auth.py --role super_admin - MySQL 数据库可连接 (pymysql) """ import allure import pytest from tests.core.db_helper import update_risk_control_status from tests.pages.admin.freight_accounting_page import FreightAccountingPage from tests.pages.driver.freight_flow_page import DriverFreightFlowPage pytestmark = [pytest.mark.cross_end, pytest.mark.p0, pytest.mark.smoke] @allure.epic("运八网络货运平台") @allure.feature("跨端 E2E — 司机接单到管理端核算打款") class TestDriverToSettlement: """完整业务流程: 司机 APP 接单→装货→卸货 → Web 管理端核算→打款。 测试覆盖: - 司机 APP: 货源浏览、接单、装货(含拍照上传、合同确认)、卸货(含拍照上传) - Web 管理端: 运费核算、运单审核、垫资-财务打款(含验证码)、垫资-货主打款 - 数据库: SQL 更新风控状态(运费核算查询无数据时自动执行) 用例ID: TC-D2S-001 用例名称: 司机APP接单到管理端核算打款完整流程 优先级: P0 标签: cross_end, smoke """ @allure.story("司机APP接单到管理端核算打款完整流程") @allure.title("TC-D2S-001 司机APP接单到管理端核算打款完整流程") @allure.tag("cross_end", "smoke") def test_driver_to_settlement_full_flow( self, admin_page, admin_config, app_driver, ensure_admin_login, ensure_driver_login, cross_end_context, logger, ): """ 用例ID: TC-D2S-001 用例名称: 司机APP接单到管理端核算打款完整流程 优先级: P0 标签: cross_end, smoke 验证从司机 APP 接单到管理端核算打款的完整跨端业务流程。 """ logger.info("=" * 60) logger.info("跨端 E2E: 司机APP → 管理端核算打款 完整流程开始") logger.info("=" * 60) # ── 登录确认 ── ensure_admin_login("super_admin") ensure_driver_login(app_driver) # ── 初始化 Page Objects ── driver_flow = DriverFreightFlowPage(app_driver) admin_accounting = FreightAccountingPage(admin_page, admin_base_url=admin_config["base_url"]) # ════════════════════════════════════════════════════════════ # Phase 1: 司机 Android APP — 接单 + 装货 + 卸货 # ════════════════════════════════════════════════════════════ with allure.step("Phase 1: 司机 APP — 接单流程"): driver_flow.accept_order_flow(quantity="1") driver_flow.screenshot("step_accept_order") logger.info(" -> 接单流程完成") with allure.step("Phase 1: 司机 APP — 装货流程"): driver_flow.load_goods_flow(weight="10") driver_flow.screenshot("step_load_goods") logger.info(" -> 装货流程完成") with allure.step("Phase 1: 司机 APP — 卸货流程"): driver_flow.unload_goods_flow(weight="10") driver_flow.screenshot("step_unload_goods") logger.info(" -> 卸货流程完成") with allure.step("Phase 1: 司机 APP — 获取运输单号"): transport_order_no = driver_flow.get_transport_order_no() cross_end_context["order_no"] = transport_order_no logger.info(f" -> 运输单号: {transport_order_no}") # ════════════════════════════════════════════════════════════ # Phase 2: Web 管理端 — 核算 + 审核 + 打款 # ════════════════════════════════════════════════════════════ with allure.step("Phase 2: Web管理端 — 运费核算(首次查询无数据时自动 SQL 重试)"): admin_accounting.do_freight_accounting( transport_order_no, retry_sql=lambda: update_risk_control_status(transport_order_no, status=1), ) cross_end_context["accounting_done"] = True logger.info(f" -> 运费核算完成: {transport_order_no}") with allure.step("Phase 2: Web管理端 — 运单审核"): admin_accounting.do_waybill_audit(transport_order_no) cross_end_context["review_done"] = True logger.info(f" -> 运单审核完成: {transport_order_no}") with allure.step("Phase 2: Web管理端 — 垫资-财务打款"): admin_accounting.do_finance_payment(transport_order_no, verify_code="1234") logger.info(f" -> 垫资-财务打款完成: {transport_order_no}") with allure.step("Phase 2: Web管理端 — 垫资-货主打款"): admin_accounting.do_shipper_payment(transport_order_no) logger.info(f" -> 垫资-货主打款完成: {transport_order_no}") # ════════════════════════════════════════════════════════════ # 最终验证 # ════════════════════════════════════════════════════════════ logger.info("=" * 60) logger.info("跨端 E2E: 司机APP → 管理端核算打款 完整流程结束!") logger.info(f" 运输单号: {cross_end_context['order_no']}") logger.info(f" 核算完成: {cross_end_context['accounting_done']}") logger.info(f" 审核完成: {cross_end_context['review_done']}") logger.info("=" * 60) assert cross_end_context["order_no"], "运输单号不能为空" assert cross_end_context["accounting_done"], "核算未完成" assert cross_end_context["review_done"], "审核未完成" @allure.epic("运八网络货运平台") @allure.feature("跨端 E2E — 司机接单到管理端核算打款") class TestDriverToSettlementTeamLeader: """车队长全额收款流程: 司机 APP 接单→装货→卸货 → Web 管理端核算(车队长全额收款)→打款。 与基础流程的区别: 在运费核算编辑弹窗中,额外选择"车队长"+车队长"全额收款"模式, 然后继续核算→审核→打款。 用例ID: TC-D2S-002 用例名称: 司机APP接单到管理端核算打款-车队长全额收款流程 优先级: P0 标签: cross_end, smoke """ @allure.story("司机APP接单到管理端核算打款-车队长全额收款流程") @allure.title("TC-D2S-002 司机APP接单到管理端核算打款-车队长全额收款流程") @allure.tag("cross_end", "smoke") def test_driver_to_settlement_team_leader_flow( self, admin_page, admin_config, app_driver, ensure_admin_login, ensure_driver_login, cross_end_context, logger, ): """ 用例ID: TC-D2S-002 用例名称: 司机APP接单到管理端核算打款-车队长全额收款流程 优先级: P0 标签: cross_end, smoke 验证司机 APP 接单→管理端核算(车队长全额收款模式)→打款的完整跨端业务流程。 """ logger.info("=" * 60) logger.info("跨端 E2E: 司机APP → 管理端核算打款(车队长全额收款)完整流程开始") logger.info("=" * 60) # ── 登录确认 ── ensure_admin_login("super_admin") ensure_driver_login(app_driver) # ── 初始化 Page Objects ── driver_flow = DriverFreightFlowPage(app_driver) admin_accounting = FreightAccountingPage(admin_page, admin_base_url=admin_config["base_url"]) # ════════════════════════════════════════════════════════════ # Phase 1: 司机 Android APP — 接单 + 装货 + 卸货 # ════════════════════════════════════════════════════════════ with allure.step("Phase 1: 司机 APP — 接单流程"): driver_flow.accept_order_flow(quantity="1") driver_flow.screenshot("step_accept_order") logger.info(" -> 接单流程完成") with allure.step("Phase 1: 司机 APP — 装货流程"): driver_flow.load_goods_flow(weight="10") driver_flow.screenshot("step_load_goods") logger.info(" -> 装货流程完成") with allure.step("Phase 1: 司机 APP — 卸货流程"): driver_flow.unload_goods_flow(weight="10") driver_flow.screenshot("step_unload_goods") logger.info(" -> 卸货流程完成") with allure.step("Phase 1: 司机 APP — 获取运输单号"): transport_order_no = driver_flow.get_transport_order_no() cross_end_context["order_no"] = transport_order_no logger.info(f" -> 运输单号: {transport_order_no}") # ════════════════════════════════════════════════════════════ # Phase 2: Web 管理端 — 核算(车队长全额收款) + 审核 + 打款 # ════════════════════════════════════════════════════════════ with allure.step("Phase 2: Web管理端 — 运费核算(车队长全额收款模式)"): admin_accounting.do_freight_accounting( transport_order_no, retry_sql=lambda: update_risk_control_status(transport_order_no, status=1), team_leader_payment=True, ) cross_end_context["accounting_done"] = True logger.info(f" -> 运费核算完成(车队长全额收款): {transport_order_no}") with allure.step("Phase 2: Web管理端 — 运单审核"): admin_accounting.do_waybill_audit(transport_order_no) cross_end_context["review_done"] = True logger.info(f" -> 运单审核完成: {transport_order_no}") with allure.step("Phase 2: Web管理端 — 垫资-财务打款"): admin_accounting.do_finance_payment(transport_order_no, verify_code="1234") logger.info(f" -> 垫资-财务打款完成: {transport_order_no}") with allure.step("Phase 2: Web管理端 — 垫资-货主打款"): admin_accounting.do_shipper_payment(transport_order_no) logger.info(f" -> 垫资-货主打款完成: {transport_order_no}") # ════════════════════════════════════════════════════════════ # 最终验证 # ════════════════════════════════════════════════════════════ logger.info("=" * 60) logger.info("跨端 E2E: 司机APP → 管理端核算打款(车队长全额收款)完整流程结束!") logger.info(f" 运输单号: {cross_end_context['order_no']}") logger.info(f" 核算完成: {cross_end_context['accounting_done']}") logger.info(f" 审核完成: {cross_end_context['review_done']}") logger.info("=" * 60) assert cross_end_context["order_no"], "运输单号不能为空" assert cross_end_context["accounting_done"], "核算未完成" assert cross_end_context["review_done"], "审核未完成"