126 lines
4.5 KiB
Python
126 lines
4.5 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
from decimal import Decimal
|
|
|
|
from sqlalchemy import BigInteger, create_engine
|
|
from sqlalchemy.ext.compiler import compiles
|
|
from sqlalchemy.orm import Session, sessionmaker
|
|
|
|
|
|
@compiles(BigInteger, "sqlite")
|
|
def _compile_bigint_for_sqlite(type_, compiler, **kw) -> str:
|
|
_ = type_, compiler, kw
|
|
return "INTEGER"
|
|
|
|
|
|
import app.models.master_data # noqa: E402,F401
|
|
import app.models.miniapp # noqa: E402,F401
|
|
import app.models.operations # noqa: E402,F401
|
|
import app.models.org # noqa: E402,F401
|
|
import app.models.planning # noqa: E402,F401
|
|
import app.models.sales # noqa: E402,F401
|
|
from app.models.base import Base # noqa: E402
|
|
from app.models.master_data import Item, Warehouse # noqa: E402
|
|
from app.models.operations import StockLot # noqa: E402
|
|
from app.services.system_config import RAW_MATERIAL_LOT_PREFIX_CONFIG_CODE, upsert_system_config # noqa: E402
|
|
from app.services.operations import build_inventory_lot_no # noqa: E402
|
|
|
|
|
|
class InventoryLotNumberingTest(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
engine = create_engine("sqlite+pysqlite:///:memory:", future=True)
|
|
Base.metadata.create_all(engine)
|
|
self.SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)
|
|
self.db: Session = self.SessionLocal()
|
|
self.material = Item(
|
|
id=1,
|
|
item_code="110501000185",
|
|
item_name="左右后纵梁后段毛坯",
|
|
item_type="RAW_MATERIAL",
|
|
unit_weight_kg=Decimal("1"),
|
|
status="ACTIVE",
|
|
)
|
|
self.other_material = Item(
|
|
id=2,
|
|
item_code="110501000186",
|
|
item_name="其他原材料",
|
|
item_type="RAW_MATERIAL",
|
|
unit_weight_kg=Decimal("1"),
|
|
status="ACTIVE",
|
|
)
|
|
self.warehouse = Warehouse(
|
|
id=1,
|
|
warehouse_code="WH-RAW",
|
|
warehouse_name="原材料库",
|
|
warehouse_type="RAW",
|
|
status="ACTIVE",
|
|
)
|
|
self.db.add_all([self.material, self.other_material, self.warehouse])
|
|
self.db.commit()
|
|
|
|
def tearDown(self) -> None:
|
|
self.db.close()
|
|
|
|
def test_inventory_lot_no_starts_from_global_prefix_sequence(self) -> None:
|
|
self.assertEqual(build_inventory_lot_no(self.db, self.material.id), "YL0001")
|
|
|
|
def test_inventory_lot_no_increments_from_existing_lot_for_different_material(self) -> None:
|
|
self.db.add(
|
|
StockLot(
|
|
lot_no="YL0001",
|
|
lot_role="INBOUND_RAW",
|
|
item_id=self.other_material.id,
|
|
warehouse_id=self.warehouse.id,
|
|
source_doc_type="TEST",
|
|
source_doc_id=1,
|
|
inbound_qty=Decimal("0"),
|
|
inbound_weight_kg=Decimal("100"),
|
|
remaining_qty=Decimal("0"),
|
|
remaining_weight_kg=Decimal("100"),
|
|
locked_qty=Decimal("0"),
|
|
locked_weight_kg=Decimal("0"),
|
|
unit_cost=Decimal("5"),
|
|
quality_status="PASS",
|
|
status="AVAILABLE",
|
|
)
|
|
)
|
|
self.db.commit()
|
|
|
|
self.assertEqual(build_inventory_lot_no(self.db, self.material.id), "YL0002")
|
|
|
|
def test_inventory_lot_no_uses_natural_width_after_four_digits(self) -> None:
|
|
self.db.add(
|
|
StockLot(
|
|
lot_no="YL9999",
|
|
lot_role="INBOUND_RAW",
|
|
item_id=self.material.id,
|
|
warehouse_id=self.warehouse.id,
|
|
source_doc_type="TEST",
|
|
source_doc_id=1,
|
|
inbound_qty=Decimal("0"),
|
|
inbound_weight_kg=Decimal("100"),
|
|
remaining_qty=Decimal("0"),
|
|
remaining_weight_kg=Decimal("100"),
|
|
locked_qty=Decimal("0"),
|
|
locked_weight_kg=Decimal("0"),
|
|
unit_cost=Decimal("5"),
|
|
quality_status="PASS",
|
|
status="AVAILABLE",
|
|
)
|
|
)
|
|
self.db.commit()
|
|
|
|
self.assertEqual(build_inventory_lot_no(self.db, self.material.id), "YL10000")
|
|
|
|
def test_inventory_lot_no_uses_configured_prefix(self) -> None:
|
|
upsert_system_config(
|
|
self.db,
|
|
config_code=RAW_MATERIAL_LOT_PREFIX_CONFIG_CODE,
|
|
config_name="原材料库存批次号前缀",
|
|
config_value="rm",
|
|
)
|
|
self.db.commit()
|
|
|
|
self.assertEqual(build_inventory_lot_no(self.db, self.material.id), "RM0001")
|