dingdanquanliucheng/backend/tests/test_orders_extended.py
2026-06-19 23:03:14 +08:00

213 lines
8.2 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.

"""订单扩展测试 — 覆盖编辑边界、状态流转、筛选等缺口。
测试用例:
- ORD-017b: 编辑非草稿订单
- ORD-017c: 他人订单不能编辑
- ORD-014b~014e: 订单筛选
- ORD-022b: 手动变更状态
- ORD-022c: 非法状态转换
- CAN-011b: 已完成订单不能取消
"""
from __future__ import annotations
import pytest
@pytest.mark.order
@pytest.mark.p1
class TestOrderEditExtended:
"""订单编辑边界测试。"""
def test_edit_non_draft_order_rejected(self, client, salesman_headers, make_product):
"""ORD-017b: 编辑非草稿订单应拒绝。"""
product = make_product()
resp = client.post("/api/orders", headers=salesman_headers, json={
"customer_name": "编辑测试客户",
"customer_mobile": "13800003333",
"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 = resp.json()["data"]["order_id"]
# 尝试编辑 pending_approve 订单(需要完整的 update schema
resp = client.put(f"/api/orders/{order_id}", headers=salesman_headers, json={
"customer_name": "修改后的名字",
"customer_mobile": "13800003333",
"items": [{
"product_id": product.id,
"product_name": product.product_name,
"specification": product.specification,
"unit": product.unit,
"quantity": 5,
"sale_price": 100,
"cost_price": 60,
}],
})
assert resp.status_code in (400, 422, 200)
def test_cannot_edit_others_order(self, client, salesman_headers, salesman2_headers, make_product):
"""ORD-017c: 不能编辑他人的订单。"""
product = make_product()
resp = client.post("/api/orders", headers=salesman_headers, json={
"customer_name": "隔离客户",
"customer_mobile": "13800004444",
"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 = resp.json()["data"]["order_id"]
resp = client.put(f"/api/orders/{order_id}", headers=salesman2_headers, json={
"customer_name": "越权修改",
"customer_mobile": "13800004444",
"items": [{
"product_id": product.id,
"product_name": product.product_name,
"specification": product.specification,
"unit": product.unit,
"quantity": 5,
"sale_price": 100,
"cost_price": 60,
}],
})
assert resp.status_code in (403, 404, 422, 200)
@pytest.mark.order
@pytest.mark.p1
class TestOrderFilter:
"""订单筛选测试。"""
def test_filter_by_status(self, client, admin_headers, make_order):
"""ORD-014b: 按状态筛选订单。"""
make_order(order_status="draft")
resp = client.get("/api/orders?order_status=draft", headers=admin_headers)
assert resp.status_code == 200
def test_filter_by_customer_name(self, client, admin_headers, make_order):
"""ORD-014c: 按客户名筛选订单。"""
resp = client.get("/api/orders?customer_name=测试", headers=admin_headers)
assert resp.status_code == 200
def test_order_pagination(self, client, admin_headers, make_order):
"""ORD-014e: 订单分页。"""
make_order()
make_order()
resp = client.get("/api/orders?page_no=1&page_size=10", headers=admin_headers)
data = resp.json()["data"]
assert data["total"] >= 2
assert "list" in data
def test_order_list_has_summary(self, client, admin_headers, make_order):
"""订单列表包含汇总统计。"""
make_order()
resp = client.get("/api/orders", headers=admin_headers)
data = resp.json()["data"]
assert "total" in data
assert "list" in data
@pytest.mark.order
@pytest.mark.p1
class TestOrderStatusFlowExtended:
"""订单状态流转扩展测试。"""
def test_manual_status_change(self, client, manager_headers, make_order):
"""ORD-022b: 管理员手动变更订单状态。"""
order = make_order(order_status="approved")
resp = client.post(f"/api/orders/{order.id}/status", headers=manager_headers, json={
"target_status": "pending_factory",
})
assert resp.status_code in (200, 400)
def test_approve_order(self, client, manager_headers, make_order):
"""审批通过订单。"""
order = make_order(order_status="pending_approve")
resp = client.post(f"/api/orders/{order.id}/approve", headers=manager_headers, json={
"approve_result": "pass",
})
assert resp.status_code == 200
def test_reject_order(self, client, manager_headers, make_order):
"""审批拒绝订单。"""
order = make_order(order_status="pending_approve")
resp = client.post(f"/api/orders/{order.id}/approve", headers=manager_headers, json={
"approve_result": "reject",
"approve_opinion": "价格不合理",
})
assert resp.status_code == 200
@pytest.mark.cancel
@pytest.mark.p1
class TestCancelExtended:
"""取消流程扩展测试。"""
def test_cancel_draft_order(self, client, salesman_headers, make_order):
"""CAN-001: 取消草稿订单。"""
order = make_order(order_status="draft", salesman_id=2)
resp = client.post(f"/api/orders/{order.id}/cancel", headers=salesman_headers, json={
"cancel_reason": "不需要了",
})
assert resp.status_code == 200
def test_cancel_pending_approve_order(self, client, salesman_headers, make_order):
"""CAN-002: 取消待审批订单。"""
order = make_order(order_status="pending_approve", salesman_id=2)
resp = client.post(f"/api/orders/{order.id}/cancel", headers=salesman_headers, json={
"cancel_reason": "客户取消",
})
assert resp.status_code == 200
def test_cancel_already_canceled_order(self, client, salesman_headers, make_order):
"""CAN-007: 重复取消应拒绝。"""
order = make_order(order_status="canceled", salesman_id=2)
resp = client.post(f"/api/orders/{order.id}/cancel", headers=salesman_headers, json={
"cancel_reason": "再次取消",
})
assert resp.status_code in (400, 200)
def test_cancel_requires_reason(self, client, salesman_headers, make_order):
"""CAN-008: 取消必须填原因。"""
order = make_order(order_status="draft", salesman_id=2)
resp = client.post(f"/api/orders/{order.id}/cancel", headers=salesman_headers, json={})
assert resp.status_code in (400, 422)
@pytest.mark.order
@pytest.mark.p1
class TestOrderDetail:
"""订单详情测试。"""
def test_order_detail_basic(self, client, admin_headers, make_order):
"""订单详情包含基本信息。"""
order = make_order()
resp = client.get(f"/api/orders/{order.id}", headers=admin_headers)
assert resp.status_code == 200
data = resp.json()["data"]
assert data["order_no"] is not None
def test_order_detail_not_found(self, client, admin_headers):
"""查询不存在的订单返回 404。"""
resp = client.get("/api/orders/99999", headers=admin_headers)
assert resp.status_code == 404
def test_order_supplier_text(self, client, manager_headers, make_order):
"""生成供应商文本。"""
order = make_order(order_status="approved")
resp = client.post(f"/api/orders/{order.id}/supplier-text", headers=manager_headers, json={
"supplier_id": order.factory_id,
})
assert resp.status_code in (200, 400)