AI-Pricing-Agent/dashboard/line.py

41 lines
1.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""Ranking rules for a product line.
Kept out of ``app.py`` so it can be imported and tested without executing the
Streamlit page. Deciding which 10 of 99 products to spend an hour analyzing is
real logic, not presentation.
"""
from __future__ import annotations
# Label shown in the picker → (field to sort on, descending?).
# Ordered by how often each is the right question to ask of a line.
LINE_SORTS: dict[str, tuple[str, bool]] = {
"Sales velocity (30d)": ("avg_30d", True),
"Inventory on hand": ("inventory", True),
"Cover days — lowest first": ("cover_days", False),
"Reorder size (min PO)": ("min_po_quantity", True),
"AZ": ("sku", False),
}
def line_sort_key(product: dict, field: str):
"""Sort key tolerating both text and numeric fields, and missing values.
Two things it has to get right:
* **Mixed types.** A single numeric key raises ``TypeError`` the moment the
user picks AZ, because it compares ``str`` against ``0``.
* **Missing values sort last, in either direction.** A SKU with no cover-days
reading is not the most urgent item in the line — but a plain ``or 0``
makes it exactly that when sorting ascending.
"""
value = product.get(field)
if isinstance(value, str):
return (False, value.upper())
return (value is None, value if value is not None else 0)
def rank(products: list[dict], sort_label: str) -> list[dict]:
"""Order a line by one of `LINE_SORTS`, falling back to the first rule."""
field, reverse = LINE_SORTS.get(sort_label, next(iter(LINE_SORTS.values())))
return sorted(products, key=lambda p: line_sort_key(p, field), reverse=reverse)