93 lines
3.5 KiB
Python
93 lines
3.5 KiB
Python
"""workflows/inventory.py — stock reads + adjust_inventory (plan §6, §10)."""
|
|
|
|
import pytest
|
|
|
|
from mcp_server.errors import ClarificationNeededError, NotFoundError
|
|
|
|
|
|
# --- stock reads ------------------------------------------------------------
|
|
|
|
|
|
async def test_stock_for_resource_lists_containers(inventory):
|
|
stock = await inventory.stock_for_resource("ethanol_absolute")
|
|
assert [s.container_id for s in stock] == [31, 32]
|
|
assert stock[0].available == 50.0
|
|
assert stock[0].unit == "mL"
|
|
assert stock[0].amount == "50.0 mL"
|
|
|
|
|
|
async def test_stock_for_unknown_resource_raises_clarification(inventory, resolver_stub):
|
|
resolver_stub.mappings.clear()
|
|
with pytest.raises(ClarificationNeededError):
|
|
await inventory.stock_for_resource("unobtainium")
|
|
|
|
|
|
# --- adjust_inventory -------------------------------------------------------
|
|
|
|
|
|
async def test_adjust_adds_to_container_by_id(inventory, client):
|
|
result = await inventory.adjust_inventory(amount=500.0, unit="mL", container_id=31)
|
|
assert result.ok is True
|
|
assert result.container_id == 31
|
|
assert result.amount == "500.0 mL"
|
|
assert result.remaining == "550.0 mL"
|
|
assert client.items[12].containers[0].qty_stored == 550.0
|
|
|
|
|
|
async def test_adjust_supports_correction_negative_delta(inventory, client):
|
|
await inventory.adjust_inventory(amount=-2.0, unit="mL", container_id=31)
|
|
assert client.items[12].containers[0].qty_stored == 48.0
|
|
|
|
|
|
async def test_adjust_by_resource_key_uses_allocable_container(inventory, client):
|
|
result = await inventory.adjust_inventory(
|
|
amount=100.0, unit="mL", resource_key="ethanol_absolute"
|
|
)
|
|
assert result.resource_key == "ethanol_absolute"
|
|
assert result.container_id == 31
|
|
assert result.remaining == "150.0 mL"
|
|
|
|
|
|
async def test_adjust_converts_units(inventory, client):
|
|
"""“Add half a litre” against an mL-stocked container."""
|
|
await inventory.adjust_inventory(amount=0.5, unit="L", container_id=31)
|
|
assert client.items[12].containers[0].qty_stored == 550.0
|
|
|
|
|
|
async def test_adjust_rejects_non_whitelisted_unit(inventory):
|
|
with pytest.raises(ClarificationNeededError):
|
|
await inventory.adjust_inventory(amount=1.0, unit="fl-oz", container_id=31)
|
|
|
|
|
|
async def test_adjust_rejects_cross_dimension_unit(inventory):
|
|
with pytest.raises(ClarificationNeededError):
|
|
await inventory.adjust_inventory(amount=5.0, unit="g", container_id=31)
|
|
|
|
|
|
async def test_adjust_unknown_container_fails_cleanly(inventory):
|
|
with pytest.raises(NotFoundError):
|
|
await inventory.adjust_inventory(amount=1.0, unit="mL", container_id=9999)
|
|
|
|
|
|
async def test_adjust_requires_container_or_resource(inventory):
|
|
with pytest.raises(ClarificationNeededError):
|
|
await inventory.adjust_inventory(amount=1.0, unit="mL")
|
|
|
|
|
|
async def test_adjust_is_journaled(inventory, journal):
|
|
await inventory.adjust_inventory(amount=500.0, unit="mL", container_id=31)
|
|
assert journal.db_path.exists()
|
|
|
|
|
|
async def test_adjust_failure_does_not_silently_lose_data(inventory, client, monkeypatch):
|
|
"""If the write fails, the workflow surfaces the error (journaled saga)."""
|
|
from mcp_server.errors import ApiError
|
|
|
|
async def fail_write(entity_type, entity_id, subitem_id, qty_stored):
|
|
raise ApiError("write refused")
|
|
|
|
monkeypatch.setattr(inventory.client, "set_container_quantity", fail_write)
|
|
with pytest.raises(ApiError):
|
|
await inventory.adjust_inventory(amount=500.0, unit="mL", container_id=31)
|
|
assert client.items[12].containers[0].qty_stored == 50.0
|