from datetime import datetime from sqlalchemy import create_engine, text from sqlalchemy.orm import sessionmaker from app.routers import reports def _session(): engine = create_engine("sqlite+pysqlite:///:memory:", future=True) with engine.begin() as connection: connection.execute(text("create table md_item (id integer primary key, item_code text, item_name text)")) connection.execute( text( """ create table pp_production_batch_ledger ( id integer primary key, material_lot_no text, product_item_id integer, status text, miniapp_selectable integer ) """ ) ) SessionLocal = sessionmaker(bind=engine, future=True) return SessionLocal() def test_raw_material_batch_options_returns_material_lot_numbers_for_product_process(monkeypatch): class FrozenDateTime(datetime): @classmethod def now(cls, tz=None): # noqa: ANN001 _ = tz return cls(2026, 6, 2, 10, 0, 0) monkeypatch.setattr(reports, "datetime", FrozenDateTime) db = _session() try: db.execute( text("insert into md_item (id, item_code, item_name) values (1, 'FG-001', '钢制碗'), (2, 'FG-002', '钢制盆')") ) db.execute( text( """ insert into pp_production_batch_ledger (id, material_lot_no, product_item_id, status, miniapp_selectable) values (1, 'YL0001', 1, '在生产', 1), (2, 'YL0002', 1, '在生产', 1), (3, 'YL0003', 1, '锁单', 0), (4, '', 1, '在生产', 1), (5, null, 1, '在生产', 1), (6, 'YL0004', 2, '在生产', 1) """ ) ) db.commit() options = reports._raw_material_batch_options( db, project_no="FG-001", product_name="钢制碗", process_name="1序", ) assert options == ["YL0001", "YL0002"] finally: db.close() def test_raw_material_batch_options_matches_project_no_when_product_name_is_empty(monkeypatch): class FrozenDateTime(datetime): @classmethod def now(cls, tz=None): # noqa: ANN001 _ = tz return cls(2026, 6, 2, 10, 0, 0) monkeypatch.setattr(reports, "datetime", FrozenDateTime) db = _session() try: db.execute(text("insert into md_item (id, item_code, item_name) values (1, 'FG-001', '钢制碗')")) db.execute( text( """ insert into pp_production_batch_ledger (id, material_lot_no, product_item_id, status, miniapp_selectable) values (1, 'YL0001', 1, '在生产', 1) """ ) ) db.commit() options = reports._raw_material_batch_options( db, project_no="FG-001", product_name="", process_name="1序", ) assert options == ["YL0001"] finally: db.close() def test_raw_material_batch_options_uses_project_no_to_narrow_duplicate_product_names(monkeypatch): class FrozenDateTime(datetime): @classmethod def now(cls, tz=None): # noqa: ANN001 _ = tz return cls(2026, 6, 2, 10, 0, 0) monkeypatch.setattr(reports, "datetime", FrozenDateTime) db = _session() try: db.execute( text( """ insert into md_item (id, item_code, item_name) values (1, 'FG-001', '钢制碗'), (2, 'FG-002', '钢制碗') """ ) ) db.execute( text( """ insert into pp_production_batch_ledger (id, material_lot_no, product_item_id, status, miniapp_selectable) values (1, 'YL0001', 1, '在生产', 1), (2, 'YL0002', 2, '在生产', 1) """ ) ) db.commit() options = reports._raw_material_batch_options( db, project_no="FG-001", product_name="钢制碗", process_name="1序", ) assert options == ["YL0001"] finally: db.close() def test_raw_material_batch_options_excludes_locked_and_unselectable_ledgers(monkeypatch): class FrozenDateTime(datetime): @classmethod def now(cls, tz=None): # noqa: ANN001 _ = tz return cls(2026, 6, 2, 10, 0, 0) monkeypatch.setattr(reports, "datetime", FrozenDateTime) db = _session() try: db.execute(text("insert into md_item (id, item_code, item_name) values (1, 'FG-001', '钢制碗')")) db.execute( text( """ insert into pp_production_batch_ledger (id, material_lot_no, product_item_id, status, miniapp_selectable) values (1, 'YL0001', 1, '锁单', 0), (2, 'YL0002', 1, '在生产', 0), (3, 'YL0003', 1, '在生产', 1) """ ) ) db.commit() options = reports._raw_material_batch_options( db, project_no="FG-001", product_name="钢制碗", process_name="1序", ) assert options == ["YL0003"] finally: db.close()