"""Product-line discovery and ranking (pure, no network).""" from __future__ import annotations import pytest from dashboard.line import LINE_SORTS, rank from pricing_agent.cosmos.models import LineProduct def _make(sku, inv=0.0, avg30=0.0, cover=None, minpo=0.0) -> LineProduct: p = LineProduct.model_validate({ "sku": sku, "inventory": inv, "averageSale30Days": avg30, "minPoQuantity": minpo}) p.cover_days = cover return p # ---------------------------------------------------------------- size parsing @pytest.mark.parametrize("sku,expected", [ ("UBMICROFIBERDUVETQUEENWHITE", "Queen"), ("UBMICROFIBERDUVETKINGWHITE2", "King"), ("UBMICROFIBERDUVETTWINGREY", "Twin"), ("UBMICROFIBERDUVETFULLNAVY", "Full"), ("UBMICROFIBERDUVETCALKINGWHITE", "Calking"), ("UBSOMETHINGELSE", "Other"), ]) def test_size_is_read_from_the_sku(sku, expected): assert _make(sku).size == expected def test_calking_is_not_mistaken_for_king(): """CALKING contains KING, so the order tokens are matched in matters.""" assert _make("UBMICROFIBERDUVETCALKINGGREY").size == "Calking" def test_line_product_maps_the_cosmos_aliases(): p = LineProduct.model_validate({ "sku": "UBMICROFIBERDUVETQUEENWHITE", "asin": "B00NWPUKMS", "inventory": 6623, "averageSale30Days": 188, "averageSale6Months": 193, "minPoQuantity": 11280, "parentAsin": "B0DMGS61XY"}) assert (p.inventory, p.avg_30d, p.avg_6m, p.min_po_quantity) == ( 6623, 188, 193, 11280) assert p.asin == "B00NWPUKMS" and p.parent_asin == "B0DMGS61XY" # ---------------------------------------------------------------- ranking ROWS = [ {"sku": "B_MID", "inventory": 500.0, "avg_30d": 20.0, "cover_days": 90, "min_po_quantity": 0.0}, {"sku": "A_TOP", "inventory": 100.0, "avg_30d": 50.0, "cover_days": 5, "min_po_quantity": 900.0}, {"sku": "C_DEAD", "inventory": 0.0, "avg_30d": 0.0, "cover_days": None, "min_po_quantity": 0.0}, ] def _order(label): return [r["sku"] for r in rank(ROWS, label)] def test_rank_by_velocity_puts_the_biggest_seller_first(): assert _order("Sales velocity (30d)")[0] == "A_TOP" def test_rank_by_inventory_puts_the_deepest_stock_first(): assert _order("Inventory on hand")[0] == "B_MID" def test_rank_by_cover_puts_the_most_urgent_first(): assert _order("Cover days — lowest first")[0] == "A_TOP" def test_missing_values_sort_last_not_first(): """A SKU with no cover reading must not be presented as the most urgent.""" assert _order("Cover days — lowest first")[-1] == "C_DEAD" def test_alphabetical_sorts_text_without_blowing_up(): """A purely numeric sort key compares str against int and raises here.""" assert _order("A–Z") == ["A_TOP", "B_MID", "C_DEAD"] def test_every_offered_sort_is_usable(): """Each option in the picker must order the pool without raising.""" for label in LINE_SORTS: assert len(_order(label)) == len(ROWS) def test_unknown_sort_label_falls_back_instead_of_raising(): assert len(rank(ROWS, "not a real sort")) == len(ROWS)