mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 10:51:36 -04:00
Replace the DB-backed inventory module with a config-only design and build out food-storage tooling around it. Inventory (config-only, no database) - Each inventory is a YAML file at config/inventory/<slug>.yaml, loaded once into memory and the single source of truth. New reusable MultiFileConfig (wrolpi/common.py) manages a directory of per-entity files. - Inventory types (food/fuel/tool) seed a customizable field schema (text/number/quantity/date/select/location/calories). Unit math/aggregation moved to the frontend (mathjs); Pint dropped from the backend. - Minimal API: GET / (all inventories full), POST /, PUT /<slug> (whole- inventory save with version-based optimistic concurrency; 404 for missing), DELETE. Legacy inventories.yaml / old tables migrate to per-inventory files (pound->lb), and an alembic migration drops the tables. Frontend - New app/src/components/inventory/ package: spreadsheet-style table with Tab/Enter keyboard entry, sortable columns, expired-row highlighting, customizable field editor, and pooled cross-inventory location autocomplete. - A single useInventories store loads everything once and persists whole inventories optimistically; list/items/summary/locations derive client-side. - Summary groups items (default by Category), totals size x count, shows a calories column, and embeds a ration estimate (how long the stock lasts). Food catalog - Shared, editable catalog (config/inventory/catalog.yaml) seeded from catalog_defaults.yaml (~60 generic items, total calories per package) with merge-keep-edits + tombstones. GET/PUT /api/inventory/catalog, a management modal, and entry-row pre-fill of category/size/calories from a name match. Calculators - Generic Food Storage planner (like the Water calculator): household + editable per-person/year amounts -> total to store over a chosen duration, with women/children weighted by DGA calorie shares and an imperial/metric toggle. Also fixes ConfigFile.save() to accept nested file_names. Backend pytest and frontend jest suites updated/added throughout; alembic check clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
58 lines
2 KiB
Python
58 lines
2 KiB
Python
import pytest
|
|
|
|
from modules.inventory import common as inventory_common
|
|
|
|
|
|
@pytest.fixture
|
|
def test_inventory_configs(test_directory):
|
|
"""Use an isolated, config-only inventory store pointed at the test directory.
|
|
|
|
Ensures the shared context is attached so the config's save/switch paths work even in pure-unit tests that
|
|
do not start the app via `async_client`.
|
|
"""
|
|
from wrolpi.api_utils import api_app
|
|
from wrolpi.contexts import attach_shared_contexts
|
|
if not hasattr(api_app.shared_ctx, 'switches_lock'):
|
|
attach_shared_contexts(api_app)
|
|
|
|
(test_directory / 'config' / 'inventory').mkdir(parents=True, exist_ok=True)
|
|
inventory_common.set_test_inventories_config(True)
|
|
config = inventory_common.get_inventory_configs()
|
|
config.initialize()
|
|
try:
|
|
yield config
|
|
finally:
|
|
inventory_common.set_test_inventories_config(False)
|
|
|
|
|
|
@pytest.fixture
|
|
def test_catalog_config(test_directory):
|
|
"""Use an isolated, config-only food catalog pointed at the test directory."""
|
|
from wrolpi.api_utils import api_app
|
|
from wrolpi.contexts import attach_shared_contexts
|
|
from modules.inventory import catalog as catalog_module
|
|
if not hasattr(api_app.shared_ctx, 'switches_lock'):
|
|
attach_shared_contexts(api_app)
|
|
|
|
(test_directory / 'config' / 'inventory').mkdir(parents=True, exist_ok=True)
|
|
catalog_module.set_test_catalog_config(True)
|
|
config = catalog_module.get_catalog_config()
|
|
config.initialize()
|
|
try:
|
|
yield config
|
|
finally:
|
|
catalog_module.set_test_catalog_config(False)
|
|
|
|
|
|
@pytest.fixture
|
|
def food_inventory_factory(test_inventory_configs):
|
|
"""Create a food inventory (optionally with items) and return its slug."""
|
|
|
|
def _(name='Food Storage', inventory_type='food', items=None):
|
|
inventory = test_inventory_configs.create_inventory(name, inventory_type)
|
|
slug = inventory['slug']
|
|
if items:
|
|
test_inventory_configs.save_inventory(slug, dict(items=items))
|
|
return slug
|
|
|
|
return _
|