"""Unit-тесты stock forecast.""" from __future__ import annotations import unittest from app import create_app, db from app.models import ComponentStock from app.services.analytics.stock_forecast import build_stock_forecast from app.services.daily_plan.skips import skip_ingredient from app.services.setup_state import mark_setup_complete from app.timeutil import utc_now_naive from tests.helpers.dispenser_recipe_fixtures import ( E2E_DISP_COMP, E2E_DISP_RECIPE_1, seed_dispenser_period_recipes, ) from tests.helpers.zootech_test_helpers import ZootechTestConfig class AnalyticsStockForecastTests(unittest.TestCase): def setUp(self) -> None: self.app = create_app(ZootechTestConfig) self.ctx = self.app.app_context() self.ctx.push() db.create_all() mark_setup_complete(self.app) seed_dispenser_period_recipes() db.session.add( ComponentStock( component_id=E2E_DISP_COMP, component_name="E2E Disp компонент", total_kg=100.0, baseline_consumed_kg=0.0, stocktake_at=utc_now_naive(), updated_at=utc_now_naive(), updated_by="system", ) ) db.session.commit() def tearDown(self) -> None: db.session.remove() db.drop_all() self.ctx.pop() def test_forecast_includes_adjusted_days(self) -> None: data = build_stock_forecast(plan_date="2026-06-07") self.assertIn("items", data) item = next((i for i in data["items"] if i["component_id"] == E2E_DISP_COMP), None) self.assertIsNotNone(item) self.assertIn("daysLeftAdjusted", item) self.assertIn("daysLeftAdjustedLabel", item) def test_skip_changes_plan_today(self) -> None: before = build_stock_forecast(plan_date="2026-06-07") item_before = next(i for i in before["items"] if i["component_id"] == E2E_DISP_COMP) skip_ingredient(E2E_DISP_RECIPE_1, "e2e-disp-ing-1", "2026-06-07") after = build_stock_forecast(plan_date="2026-06-07") item_after = next(i for i in after["items"] if i["component_id"] == E2E_DISP_COMP) self.assertLess(item_after["planTodayKgPerDay"], item_before["planTodayKgPerDay"]) if __name__ == "__main__": unittest.main()