101 lines
3.5 KiB
Python
101 lines
3.5 KiB
Python
|
|
import pytest
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.anyio
|
||
|
|
async def test_material_price_history_create_updates_latest_cost(client):
|
||
|
|
resp = await client.post(
|
||
|
|
"/api/materials/1/price-history",
|
||
|
|
json={"price": 12.5, "supplier_id": 1, "remark": "latest"},
|
||
|
|
)
|
||
|
|
assert resp.status_code == 201
|
||
|
|
body = resp.json()
|
||
|
|
assert body["product_id"] == 1
|
||
|
|
assert body["price"] == 12.5
|
||
|
|
assert body["supplier_name"] == "供应商A"
|
||
|
|
|
||
|
|
history = await client.get("/api/materials/1/price-history")
|
||
|
|
assert history.status_code == 200
|
||
|
|
assert history.json()[0]["price"] == 12.5
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.anyio
|
||
|
|
async def test_material_price_trend_returns_change_summary(client):
|
||
|
|
resp1 = await client.post(
|
||
|
|
"/api/materials/1/price-history",
|
||
|
|
json={"price": 10.0, "supplier_id": 1},
|
||
|
|
)
|
||
|
|
assert resp1.status_code == 201
|
||
|
|
resp2 = await client.post(
|
||
|
|
"/api/materials/1/price-history",
|
||
|
|
json={"price": 15.0, "supplier_id": 1},
|
||
|
|
)
|
||
|
|
assert resp2.status_code == 201
|
||
|
|
|
||
|
|
trend = await client.get("/api/materials/1/price-trend", params={"months": 6})
|
||
|
|
assert trend.status_code == 200
|
||
|
|
body = trend.json()
|
||
|
|
prices = [item["price"] for item in body["price_history"]]
|
||
|
|
assert sorted(prices) == [10.0, 15.0]
|
||
|
|
assert body["current_price"] in {10.0, 15.0}
|
||
|
|
assert body["price_change"] in {5.0, -5.0}
|
||
|
|
assert body["price_change_percent"] in {50.0, -33.33}
|
||
|
|
assert len(body["price_history"]) == 2
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.anyio
|
||
|
|
async def test_material_price_trend_requires_history(client):
|
||
|
|
resp = await client.get("/api/materials/1/price-trend")
|
||
|
|
assert resp.status_code == 404
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.anyio
|
||
|
|
async def test_add_material_supplier_and_list_by_material(client):
|
||
|
|
resp = await client.post(
|
||
|
|
"/api/materials/1/suppliers",
|
||
|
|
json={"supplier_id": 1, "is_primary": True, "lead_time": 7, "min_order_quantity": 10},
|
||
|
|
)
|
||
|
|
assert resp.status_code == 400 # seeded_db 已存在主关联
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.anyio
|
||
|
|
async def test_get_material_suppliers_and_supplier_materials(client):
|
||
|
|
by_material = await client.get("/api/materials/1/suppliers")
|
||
|
|
assert by_material.status_code == 200
|
||
|
|
material_rows = by_material.json()
|
||
|
|
assert len(material_rows) == 1
|
||
|
|
assert material_rows[0]["supplier_id"] == 1
|
||
|
|
assert material_rows[0]["supplier_name"] == "供应商A"
|
||
|
|
|
||
|
|
by_supplier = await client.get("/api/materials/suppliers/1/materials")
|
||
|
|
assert by_supplier.status_code == 200
|
||
|
|
supplier_rows = by_supplier.json()
|
||
|
|
assert len(supplier_rows) == 1
|
||
|
|
assert supplier_rows[0]["product_id"] == 1
|
||
|
|
assert supplier_rows[0]["product_sku"] == "MAT-001"
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.anyio
|
||
|
|
async def test_remove_material_supplier_deletes_association(client):
|
||
|
|
resp = await client.delete("/api/materials/suppliers/1")
|
||
|
|
assert resp.status_code == 200
|
||
|
|
assert resp.json()["message"] == "物料供应商关联已删除"
|
||
|
|
|
||
|
|
by_material = await client.get("/api/materials/1/suppliers")
|
||
|
|
assert by_material.status_code == 200
|
||
|
|
assert by_material.json() == []
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.anyio
|
||
|
|
@pytest.mark.parametrize(
|
||
|
|
"url,payload,expected",
|
||
|
|
[
|
||
|
|
("/api/materials/2/price-history", {"price": 10.0}, 400),
|
||
|
|
("/api/materials/99999/price-history", {"price": 10.0}, 404),
|
||
|
|
("/api/materials/1/price-history", {"price": 10.0, "supplier_id": 99999}, 400),
|
||
|
|
("/api/materials/1/suppliers", {"supplier_id": 99999}, 400),
|
||
|
|
],
|
||
|
|
)
|
||
|
|
async def test_material_endpoints_validation(url, payload, expected, client):
|
||
|
|
resp = await client.post(url, json=payload)
|
||
|
|
assert resp.status_code == expected
|