"""Unit tests for the backend-owned ordering pricing engine.""" from __future__ import annotations from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.pool import StaticPool from app.db.session import Base from app.models.ordering import ( CatalogueProduct, CustomerPriceAssignment, CustomerProductPrice, PriceList, PriceListItem, PriceTier, ) from app.services.ordering_pricing import resolve_price CUSTOMER_ID = 1 TENANT = "test-tenant" def _session() -> Session: engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(bind=engine) return sessionmaker(bind=engine, expire_on_commit=False)() def _product(db: Session, **overrides) -> CatalogueProduct: values = { "tenant_id": TENANT, "name": "Maize 1T", "sku": "MAIZE-1T", "category": "grains", "base_price": 100.0, "min_order_quantity": 1.0, "requires_quote": False, } values.update(overrides) product = CatalogueProduct(**values) db.add(product) db.flush() return product def test_base_price_with_no_rules(): db = _session() product = _product(db) res = resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=2) assert res.unit_price == 100.0 assert res.price_source == "base" assert res.requires_quote is False assert res.line_total(2) == 200.0 def test_customer_discount_applies_to_base(): db = _session() product = _product(db) db.add(CustomerPriceAssignment(tenant_id=TENANT, client_account_id=CUSTOMER_ID, discount_percent=10.0)) db.flush() res = resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=1) assert res.unit_price == 90.0 assert res.price_source == "base" assert res.discount_percent == 10.0 def test_price_list_overrides_base(): db = _session() product = _product(db) pl = PriceList(tenant_id=TENANT, code="WHL", name="Wholesale") db.add(pl) db.flush() db.add(PriceListItem(tenant_id=TENANT, price_list_id=pl.id, product_id=product.id, unit_price=80.0)) db.add(CustomerPriceAssignment(tenant_id=TENANT, client_account_id=CUSTOMER_ID, price_list_id=pl.id, discount_percent=10.0)) db.flush() res = resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=1) # Price list wins over base+discount. assert res.unit_price == 80.0 assert res.price_source == "price_list" def test_customer_fixed_price_wins_over_price_list(): db = _session() product = _product(db) pl = PriceList(tenant_id=TENANT, code="WHL", name="Wholesale") db.add(pl) db.flush() db.add(PriceListItem(tenant_id=TENANT, price_list_id=pl.id, product_id=product.id, unit_price=80.0)) db.add(CustomerPriceAssignment(tenant_id=TENANT, client_account_id=CUSTOMER_ID, price_list_id=pl.id)) db.add( CustomerProductPrice( tenant_id=TENANT, client_account_id=CUSTOMER_ID, product_id=product.id, unit_price=72.5, rule_type="contract" ) ) db.flush() res = resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=1) assert res.unit_price == 72.5 assert res.price_source == "contract" def test_quantity_tier_wins_when_threshold_met(): db = _session() product = _product(db) cpp = CustomerProductPrice( tenant_id=TENANT, client_account_id=CUSTOMER_ID, product_id=product.id, unit_price=90.0, rule_type="fixed" ) db.add(cpp) db.flush() db.add(PriceTier(tenant_id=TENANT, customer_product_price_id=cpp.id, min_quantity=10, unit_price=85.0)) db.add(PriceTier(tenant_id=TENANT, customer_product_price_id=cpp.id, min_quantity=50, unit_price=80.0)) db.flush() # Below first tier → flat fixed price. assert resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=5).unit_price == 90.0 # Meets first tier. mid = resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=10) assert mid.unit_price == 85.0 assert mid.price_source == "tiered" # Meets highest tier. assert resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=60).unit_price == 80.0 def test_product_requires_quote(): db = _session() product = _product(db, requires_quote=True) res = resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=1) assert res.requires_quote is True assert res.unit_price is None assert res.price_source == "quote" assert res.line_total(5) is None def test_customer_quote_rule_forces_quote(): db = _session() product = _product(db) db.add( CustomerProductPrice( tenant_id=TENANT, client_account_id=CUSTOMER_ID, product_id=product.id, unit_price=None, rule_type="quote" ) ) db.flush() res = resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=1) assert res.requires_quote is True assert res.price_source == "quote" def test_no_price_falls_back_to_quote(): db = _session() product = _product(db, base_price=None) res = resolve_price(db, client_account_id=CUSTOMER_ID, product=product, quantity=1) assert res.requires_quote is True assert res.price_source == "quote"