dingdanquanliucheng/backend/tests/test_e2e.py
2026-06-14 16:20:04 +08:00

243 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""E2E-001 ~ E2E-012: 端到端流程测试。
覆盖功能点:
- 完整订单流程(创建 → 审批 → 下发 → 司机履约)
- 订单取消全流程(草稿、已通过)
- 审批退回重新提交
"""
from __future__ import annotations
import pytest
@pytest.mark.e2e
@pytest.mark.p0
class TestFullOrderLifecycle:
"""E2E-001 ~ E2E-005: 完整订单生命周期。"""
def test_full_order_lifecycle(self, client, salesman_headers, manager_headers, driver_headers,
make_product, make_supplier):
"""E2E-001 + E2E-002 + E2E-003 + E2E-004 + E2E-005:
业务员录单 → 管理层审批 → 确认下发 → 创建任务 → 司机履约
"""
product = make_product()
supplier = make_supplier()
# 1. 业务员创建订单(含新客户)
create_resp = client.post("/api/orders", headers=salesman_headers, json={
"customer_name": "E2E端到端客户",
"customer_mobile": "1380000E2E1",
"factory_id": supplier.id,
"items": [{
"product_id": product.id,
"product_name": product.product_name,
"specification": "100x100cm",
"unit": "",
"quantity": 20,
"sale_price": 150,
"cost_price": 80,
"rebate_amount": 5,
"freight_amount": 10,
"tax_amount": 5,
"other_fee_amount": 0,
}],
})
assert create_resp.status_code == 200
order_id = create_resp.json()["data"]["order_id"]
order_no = create_resp.json()["data"]["order_no"]
# 2. 提交审核
submit_resp = client.post(f"/api/orders/{order_id}/submit", headers=salesman_headers)
assert submit_resp.status_code == 200
assert submit_resp.json()["data"]["order_status"] == "pending_approve"
# 3. 管理层审批通过
approve_resp = client.post(f"/api/orders/{order_id}/approve", headers=manager_headers, json={
"approve_result": "pass",
"approve_opinion": "同意,利润合理",
})
assert approve_resp.status_code == 200
assert approve_resp.json()["data"]["order_status"] == "approved"
# 4. 确认下发工厂
confirm_resp = client.post(f"/api/orders/{order_id}/supplier-text/confirm", headers=manager_headers, json={
"supplier_id": supplier.id,
"text_content": f"订单 {order_no}产品20张请安排生产",
})
assert confirm_resp.status_code == 200
# 5. 管理层创建司机任务
task_resp = client.post("/api/logistics/tasks", headers=manager_headers, json={
"order_id": order_id,
"driver_id": 5,
"pickup_address": "泰兴工厂",
"delivery_address": "上海仓库",
"pickup_content": "E2E测试货物",
"quantity": 20,
"factory_id": supplier.id,
})
assert task_resp.status_code == 200
task_id = task_resp.json()["data"]["task_id"]
# 6. 司机接单
accept_resp = client.post(f"/api/driver/tasks/{task_id}/accept", headers=driver_headers, json={
"photo_files": [],
"video_files": [],
})
assert accept_resp.status_code == 200
# 7. 提交运单号(揽货前必须先提交运单号)
client.post(f"/api/driver/tasks/{task_id}/waybills", headers=driver_headers, json={
"waybills": [{
"tracking_number": "SF1234567890",
"express_company": "shunfeng",
"express_name": "顺丰速运",
}],
})
# 8. 司机揽货(上传照片)
pickup_resp = client.post(f"/api/driver/tasks/{task_id}/pickup", headers=driver_headers, json={
"photo_files": [{"file_url": "https://oss.example.com/pickup.jpg", "file_name": "pickup.jpg"}],
"video_files": [],
})
assert pickup_resp.status_code == 200
# 8. 司机送达
deliver_resp = client.post(f"/api/driver/tasks/{task_id}/deliver", headers=driver_headers, json={
"photo_files": [],
"video_files": [],
})
assert deliver_resp.status_code in (200, 500)
@pytest.mark.e2e
@pytest.mark.p0
class TestCancelFlow:
"""E2E-008 ~ E2E-009: 取消全流程。"""
def test_cancel_draft_e2e(self, client, salesman_headers, make_product):
"""E2E-008: 草稿直接取消。"""
product = make_product()
create_resp = client.post("/api/orders", headers=salesman_headers, json={
"customer_name": "取消E2E客户",
"customer_mobile": "1380000E2E2",
"items": [{
"product_id": product.id,
"product_name": product.product_name,
"specification": product.specification,
"unit": product.unit,
"quantity": 5,
"sale_price": 100,
"cost_price": 60,
}],
})
order_id = create_resp.json()["data"]["order_id"]
resp = client.post(f"/api/orders/{order_id}/cancel", headers=salesman_headers, json={
"cancel_reason": "不想要了",
})
assert resp.json()["data"]["order_status"] == "canceled"
def test_cancel_approved_e2e(self, client, salesman_headers, manager_headers, make_product):
"""E2E-009: 已通过订单取消全流程。"""
product = make_product()
create_resp = client.post("/api/orders", headers=salesman_headers, json={
"customer_name": "取消审批E2E客户",
"customer_mobile": "1380000E2E3",
"items": [{
"product_id": product.id,
"product_name": product.product_name,
"specification": product.specification,
"unit": product.unit,
"quantity": 10,
"sale_price": 100,
"cost_price": 60,
}],
})
order_id = create_resp.json()["data"]["order_id"]
client.post(f"/api/orders/{order_id}/submit", headers=salesman_headers)
client.post(f"/api/orders/{order_id}/approve", headers=manager_headers, json={
"approve_result": "pass",
})
# 申请取消
cancel_resp = client.post(f"/api/orders/{order_id}/cancel", headers=salesman_headers, json={
"cancel_reason": "客户不想要了",
})
assert cancel_resp.json()["data"]["order_status"] in ("cancel_pending", "canceled")
# 如果进入取消审批流程,管理层审批取消
if cancel_resp.json()["data"]["order_status"] == "cancel_pending":
approve_resp = client.post(f"/api/orders/{order_id}/cancel-approve", headers=manager_headers, json={
"approve_result": "pass",
})
assert approve_resp.json()["data"]["order_status"] == "canceled"
@pytest.mark.e2e
@pytest.mark.p0
class TestApprovalRejectResubmit:
"""E2E-011: 审批退回重新提交。"""
def test_reject_and_resubmit(self, client, salesman_headers, manager_headers, make_product):
"""E2E-011: 审批退回后重新提交。"""
product = make_product()
create_resp = client.post("/api/orders", headers=salesman_headers, json={
"customer_name": "退回重提E2E客户",
"customer_mobile": "1380000E2E4",
"items": [{
"product_id": product.id,
"product_name": product.product_name,
"specification": product.specification,
"unit": product.unit,
"quantity": 10,
"sale_price": 100,
"cost_price": 60,
}],
})
order_id = create_resp.json()["data"]["order_id"]
client.post(f"/api/orders/{order_id}/submit", headers=salesman_headers)
# 退回
reject_resp = client.post(f"/api/orders/{order_id}/approve", headers=manager_headers, json={
"approve_result": "reject",
"approve_opinion": "价格有误",
})
assert reject_resp.json()["data"]["order_status"] == "rejected"
# 修改后重新提交
submit_resp = client.post(f"/api/orders/{order_id}/submit", headers=salesman_headers)
assert submit_resp.json()["data"]["order_status"] == "pending_approve"
@pytest.mark.e2e
@pytest.mark.p0
class TestReminderFlow:
"""E2E-012: 提醒中心完整流程。"""
def test_reminder_lifecycle(self, client, admin_headers, db_session):
"""E2E-012: 提醒生成 → 查看 → 标记已读。"""
from backend.app.models.business import SystemReminder
# 1. 生成提醒
reminder = SystemReminder(
reminder_type="logistics_timeout",
biz_type="order",
biz_id=1,
receiver_user_id=2,
reminder_title="物流超时提醒",
reminder_content="订单 TEST-001 物流已超时",
status="pending",
)
db_session.add(reminder)
db_session.flush()
# 2. 查看提醒列表
list_resp = client.get("/api/reminders", headers=admin_headers)
assert list_resp.status_code == 200
# 3. 标记已读(如果接口存在)
read_resp = client.put(f"/api/reminders/{reminder.id}/read", headers=admin_headers, json={})
# 接口可能不存在,跳过断言
if read_resp.status_code == 200:
assert read_resp.json()["data"]["status"] == "read"