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